// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Runtime.CompilerServices; #if NETSTANDARD2_1_OR_GREATER using System.Runtime.InteropServices; #else using CommunityToolkit.HighPerformance.Helpers; #endif namespace CommunityToolkit.HighPerformance; /// /// A that can store a readonly reference to a value of a specified type. /// /// The type of value to reference. public readonly ref struct ReadOnlyRef { #if NETSTANDARD2_1_OR_GREATER /// /// The 1-length instance used to track the target value. /// internal readonly ReadOnlySpan Span; /// /// Initializes a new instance of the struct. /// /// The readonly reference to the target value. [MethodImpl(MethodImplOptions.AggressiveInlining)] public ReadOnlyRef(in T value) { ref T r0 = ref Unsafe.AsRef(value); Span = MemoryMarshal.CreateReadOnlySpan(ref r0, 1); } /// /// Initializes a new instance of the struct. /// /// The pointer to the target value. [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe ReadOnlyRef(void* pointer) : this(in Unsafe.AsRef(pointer)) { } /// /// Gets the readonly reference represented by the current instance. /// public ref readonly T Value { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => ref MemoryMarshal.GetReference(Span); } /// /// Implicitly converts a instance into a one. /// /// The input instance. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator ReadOnlyRef(Ref reference) { return new(in reference.Value); } #else /// /// The owner the current instance belongs to /// private readonly object owner; /// /// The target offset within the current instance is pointing to /// private readonly IntPtr offset; /// /// Initializes a new instance of the struct. /// /// The owner to create a portable reference for. /// The target offset within for the target reference. /// The parameter is not validated, and it's responsibility of the caller to ensure it's valid. [MethodImpl(MethodImplOptions.AggressiveInlining)] private ReadOnlyRef(object owner, IntPtr offset) { this.owner = owner; this.offset = offset; } /// /// Initializes a new instance of the struct. /// /// The owner to create a portable reference for. /// The target reference to point to (it must be within ). /// The parameter is not validated, and it's responsibility of the caller to ensure it's valid. [MethodImpl(MethodImplOptions.AggressiveInlining)] public ReadOnlyRef(object owner, in T value) { this.owner = owner; this.offset = ObjectMarshal.DangerousGetObjectDataByteOffset(owner, ref Unsafe.AsRef(value)); } /// /// Gets the readonly reference represented by the current instance. /// public ref readonly T Value { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => ref ObjectMarshal.DangerousGetObjectDataReferenceAt(this.owner, this.offset); } /// /// Implicitly converts a instance into a one. /// /// The input instance. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator ReadOnlyRef(Ref reference) { return new(reference.Owner, reference.Offset); } #endif /// /// Implicitly gets the value from a given instance. /// /// The input instance. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator T(ReadOnlyRef reference) { return reference.Value; } }