File: Collections\SegmentedCollectionsMarshalTests.cs
Web Access
Project: src\src\Compilers\Core\CodeAnalysisTest\Microsoft.CodeAnalysis.UnitTests.csproj (Microsoft.CodeAnalysis.UnitTests)
// 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.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis.Collections;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.UnitTests.Collections;
 
public class SegmentedCollectionsMarshalTests
{
    [Fact]
    public void SegmentedDictionary_GetValueRefOrNullRefValueType()
    {
        var dict = new SegmentedDictionary<int, Struct>
        {
            {  1, default },
            {  2, default },
        };
 
        Assert.Equal(2, dict.Count);
 
        Assert.Equal(0, dict[1].Value);
        Assert.Equal(0, dict[1].Property);
 
        Struct itemVal = dict[1];
        itemVal.Value = 1;
        itemVal.Property = 2;
 
        // Does not change values in dictionary
        Assert.Equal(0, dict[1].Value);
        Assert.Equal(0, dict[1].Property);
 
        SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 1).Value = 3;
        SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 1).Property = 4;
 
        Assert.Equal(3, dict[1].Value);
        Assert.Equal(4, dict[1].Property);
 
        ref Struct itemRef = ref SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 2);
 
        Assert.Equal(0, itemRef.Value);
        Assert.Equal(0, itemRef.Property);
 
        itemRef.Value = 5;
        itemRef.Property = 6;
 
        Assert.Equal(5, itemRef.Value);
        Assert.Equal(6, itemRef.Property);
        Assert.Equal(dict[2].Value, itemRef.Value);
        Assert.Equal(dict[2].Property, itemRef.Property);
 
        itemRef = new Struct() { Value = 7, Property = 8 };
 
        Assert.Equal(7, itemRef.Value);
        Assert.Equal(8, itemRef.Property);
        Assert.Equal(dict[2].Value, itemRef.Value);
        Assert.Equal(dict[2].Property, itemRef.Property);
 
        // Check for null refs
 
        Assert.True(Unsafe.IsNullRef(ref SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 3)));
        Assert.Throws<NullReferenceException>(() => SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 3).Value = 9);
 
        Assert.Equal(2, dict.Count);
    }
 
    [Fact]
    public void SegmentedDictionary_GetValueRefOrNullRefClass()
    {
        var dict = new SegmentedDictionary<int, IntAsObject>
        {
            {  1, new IntAsObject() },
            {  2, new IntAsObject() },
        };
 
        Assert.Equal(2, dict.Count);
 
        Assert.Equal(0, dict[1].Value);
        Assert.Equal(0, dict[1].Property);
 
        IntAsObject itemVal = dict[1];
        itemVal.Value = 1;
        itemVal.Property = 2;
 
        // Does change values in dictionary
        Assert.Equal(1, dict[1].Value);
        Assert.Equal(2, dict[1].Property);
 
        SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 1).Value = 3;
        SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 1).Property = 4;
 
        Assert.Equal(3, dict[1].Value);
        Assert.Equal(4, dict[1].Property);
 
        ref IntAsObject itemRef = ref SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 2);
 
        Assert.Equal(0, itemRef.Value);
        Assert.Equal(0, itemRef.Property);
 
        itemRef.Value = 5;
        itemRef.Property = 6;
 
        Assert.Equal(5, itemRef.Value);
        Assert.Equal(6, itemRef.Property);
        Assert.Equal(dict[2].Value, itemRef.Value);
        Assert.Equal(dict[2].Property, itemRef.Property);
 
        itemRef = new IntAsObject() { Value = 7, Property = 8 };
 
        Assert.Equal(7, itemRef.Value);
        Assert.Equal(8, itemRef.Property);
        Assert.Equal(dict[2].Value, itemRef.Value);
        Assert.Equal(dict[2].Property, itemRef.Property);
 
        // Check for null refs
 
        Assert.True(Unsafe.IsNullRef(ref SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 3)));
        Assert.Throws<NullReferenceException>(() => SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 3).Value = 9);
 
        Assert.Equal(2, dict.Count);
    }
 
    [Fact]
    public void SegmentedDictionary_GetValueRefOrNullRefLinkBreaksOnResize()
    {
        var dict = new SegmentedDictionary<int, Struct>
        {
            {  1, new Struct() },
        };
 
        Assert.Equal(1, dict.Count);
 
        ref Struct itemRef = ref SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 1);
 
        Assert.Equal(0, itemRef.Value);
        Assert.Equal(0, itemRef.Property);
 
        itemRef.Value = 1;
        itemRef.Property = 2;
 
        Assert.Equal(1, itemRef.Value);
        Assert.Equal(2, itemRef.Property);
        Assert.Equal(dict[1].Value, itemRef.Value);
        Assert.Equal(dict[1].Property, itemRef.Property);
 
        // Resize
        dict.EnsureCapacity(100);
        for (int i = 2; i <= 50; i++)
        {
            dict.Add(i, new Struct());
        }
 
        itemRef.Value = 3;
        itemRef.Property = 4;
 
        Assert.Equal(3, itemRef.Value);
        Assert.Equal(4, itemRef.Property);
 
        // Check connection broken
        Assert.NotEqual(dict[1].Value, itemRef.Value);
        Assert.NotEqual(dict[1].Property, itemRef.Property);
 
        Assert.Equal(50, dict.Count);
    }
 
    [Fact]
    public void ImmutableSegmentedDictionary_GetValueRefOrNullRefValueType()
    {
        var dict = ImmutableSegmentedDictionary.Create<int, Struct>();
        dict = dict.Add(1, default);
        dict = dict.Add(2, new Struct() { Value = 1, Property = 2 });
 
        Assert.Equal(2, dict.Count);
 
        Assert.Equal(0, dict[1].Value);
        Assert.Equal(0, dict[1].Property);
 
        Struct itemVal = dict[1];
        itemVal.Value = 1;
        itemVal.Property = 2;
 
        // Does not change values in dictionary
        Assert.Equal(0, dict[1].Value);
        Assert.Equal(0, dict[1].Property);
 
        ref readonly Struct itemRef = ref SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 2);
 
        Assert.Equal(1, itemRef.Value);
        Assert.Equal(2, itemRef.Property);
 
        Assert.Equal(dict[2].Value, itemRef.Value);
        Assert.Equal(dict[2].Property, itemRef.Property);
 
        // Check for null refs
 
        Assert.True(Unsafe.IsNullRef(ref Unsafe.AsRef(in SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 3))));
        Assert.Throws<NullReferenceException>(() => SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 3).Value);
 
        Assert.Equal(2, dict.Count);
    }
 
    [Fact]
    public void ImmutableSegmentedDictionary_GetValueRefOrNullRefClass()
    {
        var dict = ImmutableSegmentedDictionary.Create<int, IntAsObject>();
        dict = dict.Add(1, new IntAsObject());
        dict = dict.Add(2, new IntAsObject());
 
        Assert.Equal(2, dict.Count);
 
        Assert.Equal(0, dict[1].Value);
        Assert.Equal(0, dict[1].Property);
 
        IntAsObject itemVal = dict[1];
        itemVal.Value = 1;
        itemVal.Property = 2;
 
        // Does change values in dictionary
        Assert.Equal(1, dict[1].Value);
        Assert.Equal(2, dict[1].Property);
 
        SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 1).Value = 3;
        SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 1).Property = 4;
 
        Assert.Equal(3, dict[1].Value);
        Assert.Equal(4, dict[1].Property);
 
        ref readonly IntAsObject itemRef = ref SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 2);
 
        Assert.Equal(0, itemRef.Value);
        Assert.Equal(0, itemRef.Property);
 
        itemRef.Value = 5;
        itemRef.Property = 6;
 
        Assert.Equal(5, itemRef.Value);
        Assert.Equal(6, itemRef.Property);
        Assert.Equal(dict[2].Value, itemRef.Value);
        Assert.Equal(dict[2].Property, itemRef.Property);
 
        // Check for null refs
 
        Assert.True(Unsafe.IsNullRef(ref Unsafe.AsRef(in SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 3))));
        Assert.Throws<NullReferenceException>(() => SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 3).Value = 9);
 
        Assert.Equal(2, dict.Count);
    }
 
    [Fact]
    public void ImmutableSegmentedDictionary_Builder_GetValueRefOrNullRefValueType()
    {
        var dict = ImmutableSegmentedDictionary.CreateBuilder<int, Struct>();
        dict.Add(1, default);
        dict.Add(2, default);
 
        Assert.Equal(2, dict.Count);
 
        Assert.Equal(0, dict[1].Value);
        Assert.Equal(0, dict[1].Property);
 
        Struct itemVal = dict[1];
        itemVal.Value = 1;
        itemVal.Property = 2;
 
        // Does not change values in dictionary
        Assert.Equal(0, dict[1].Value);
        Assert.Equal(0, dict[1].Property);
 
        SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 1).Value = 3;
        SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 1).Property = 4;
 
        Assert.Equal(3, dict[1].Value);
        Assert.Equal(4, dict[1].Property);
 
        ref Struct itemRef = ref SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 2);
 
        Assert.Equal(0, itemRef.Value);
        Assert.Equal(0, itemRef.Property);
 
        itemRef.Value = 5;
        itemRef.Property = 6;
 
        Assert.Equal(5, itemRef.Value);
        Assert.Equal(6, itemRef.Property);
        Assert.Equal(dict[2].Value, itemRef.Value);
        Assert.Equal(dict[2].Property, itemRef.Property);
 
        itemRef = new Struct() { Value = 7, Property = 8 };
 
        Assert.Equal(7, itemRef.Value);
        Assert.Equal(8, itemRef.Property);
        Assert.Equal(dict[2].Value, itemRef.Value);
        Assert.Equal(dict[2].Property, itemRef.Property);
 
        // Check for null refs
 
        Assert.True(Unsafe.IsNullRef(ref SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 3)));
        Assert.Throws<NullReferenceException>(() => SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 3).Value = 9);
 
        Assert.Equal(2, dict.Count);
    }
 
    [Fact]
    public void ImmutableSegmentedDictionary_Builder_GetValueRefOrNullRefClass()
    {
        var dict = ImmutableSegmentedDictionary.CreateBuilder<int, IntAsObject>();
        dict.Add(1, new IntAsObject());
        dict.Add(2, new IntAsObject());
 
        Assert.Equal(2, dict.Count);
 
        Assert.Equal(0, dict[1].Value);
        Assert.Equal(0, dict[1].Property);
 
        IntAsObject itemVal = dict[1];
        itemVal.Value = 1;
        itemVal.Property = 2;
 
        // Does change values in dictionary
        Assert.Equal(1, dict[1].Value);
        Assert.Equal(2, dict[1].Property);
 
        SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 1).Value = 3;
        SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 1).Property = 4;
 
        Assert.Equal(3, dict[1].Value);
        Assert.Equal(4, dict[1].Property);
 
        ref IntAsObject itemRef = ref SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 2);
 
        Assert.Equal(0, itemRef.Value);
        Assert.Equal(0, itemRef.Property);
 
        itemRef.Value = 5;
        itemRef.Property = 6;
 
        Assert.Equal(5, itemRef.Value);
        Assert.Equal(6, itemRef.Property);
        Assert.Equal(dict[2].Value, itemRef.Value);
        Assert.Equal(dict[2].Property, itemRef.Property);
 
        itemRef = new IntAsObject() { Value = 7, Property = 8 };
 
        Assert.Equal(7, itemRef.Value);
        Assert.Equal(8, itemRef.Property);
        Assert.Equal(dict[2].Value, itemRef.Value);
        Assert.Equal(dict[2].Property, itemRef.Property);
 
        // Check for null refs
 
        Assert.True(Unsafe.IsNullRef(ref SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 3)));
        Assert.Throws<NullReferenceException>(() => SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 3).Value = 9);
 
        Assert.Equal(2, dict.Count);
    }
 
    [Fact]
    public void ImmutableSegmentedDictionary_Builder_GetValueRefOrNullRefLinkBreaksOnResize()
    {
        var dict = ImmutableSegmentedDictionary.CreateBuilder<int, Struct>();
        dict.Add(1, new Struct());
 
        Assert.Equal(1, dict.Count);
 
        ref Struct itemRef = ref SegmentedCollectionsMarshal.GetValueRefOrNullRef(dict, 1);
 
        Assert.Equal(0, itemRef.Value);
        Assert.Equal(0, itemRef.Property);
 
        itemRef.Value = 1;
        itemRef.Property = 2;
 
        Assert.Equal(1, itemRef.Value);
        Assert.Equal(2, itemRef.Property);
        Assert.Equal(dict[1].Value, itemRef.Value);
        Assert.Equal(dict[1].Property, itemRef.Property);
 
        // Resize
        dict.GetTestAccessor().GetOrCreateMutableDictionary().EnsureCapacity(100);
        for (int i = 2; i <= 50; i++)
        {
            dict.Add(i, new Struct());
        }
 
        itemRef.Value = 3;
        itemRef.Property = 4;
 
        Assert.Equal(3, itemRef.Value);
        Assert.Equal(4, itemRef.Property);
 
        // Check connection broken
        Assert.NotEqual(dict[1].Value, itemRef.Value);
        Assert.NotEqual(dict[1].Property, itemRef.Property);
 
        Assert.Equal(50, dict.Count);
    }
 
    [Fact]
    public void AsImmutableSegmentedListFromNullSegmentedList()
    {
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedList<int>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedList<int?>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedList<Guid>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedList<Guid?>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedList<string>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedList<CustomClass>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedList<ManagedCustomStruct>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedList<ManagedCustomStruct?>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedList<UnmanagedCustomStruct>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedList<UnmanagedCustomStruct?>(null).IsDefault);
    }
 
    [Fact]
    public void AsImmutableSegmentedListFromEmptySegmentedList()
    {
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedList(new SegmentedList<int>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedList(new SegmentedList<int?>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedList(new SegmentedList<Guid>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedList(new SegmentedList<Guid?>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedList(new SegmentedList<string>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedList(new SegmentedList<CustomClass>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedList(new SegmentedList<ManagedCustomStruct>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedList(new SegmentedList<ManagedCustomStruct?>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedList(new SegmentedList<UnmanagedCustomStruct>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedList(new SegmentedList<UnmanagedCustomStruct?>(0)).IsEmpty);
    }
 
    [Fact]
    public void AsImmutableSegmentedListFromExistingSegmentedList()
    {
        static void test<T>()
        {
            SegmentedList<T> list = new SegmentedList<T>(new T[17]);
            ImmutableSegmentedList<T> immutableList = SegmentedCollectionsMarshal.AsImmutableSegmentedList(list);
 
            Assert.False(immutableList.IsDefault);
            Assert.Equal(17, immutableList.Count);
 
            ref T expectedRef = ref list.GetTestAccessor().Items[0];
            ref T actualRef = ref Unsafe.AsRef(in immutableList.ItemRef(0));
 
            Assert.True(Unsafe.AreSame(ref expectedRef, ref actualRef));
        }
 
        test<int>();
        test<int?>();
        test<Guid>();
        test<Guid?>();
        test<string>();
        test<CustomClass>();
        test<ManagedCustomStruct>();
        test<ManagedCustomStruct?>();
        test<UnmanagedCustomStruct>();
        test<UnmanagedCustomStruct?>();
    }
 
    [Fact]
    public void AsSegmentedListFromDefaultImmutableSegmentedList()
    {
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedList<int>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedList<int?>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedList<Guid>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedList<Guid?>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedList<string>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedList<CustomClass>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedList<ManagedCustomStruct>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedList<ManagedCustomStruct?>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedList<UnmanagedCustomStruct>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedList<UnmanagedCustomStruct?>(default));
    }
 
    [Fact]
    public void AsSegmentedListFromEmptyImmutableSegmentedList()
    {
        static void test<T>()
        {
            SegmentedList<T>? list = SegmentedCollectionsMarshal.AsSegmentedList(ImmutableSegmentedList<T>.Empty);
 
            Assert.NotNull(list);
            Assert.Empty(list);
        }
 
        test<int>();
        test<int?>();
        test<Guid>();
        test<Guid?>();
        test<string>();
        test<CustomClass>();
        test<ManagedCustomStruct>();
        test<ManagedCustomStruct?>();
        test<UnmanagedCustomStruct>();
        test<UnmanagedCustomStruct?>();
    }
 
    [Fact]
    public void AsSegmentedListFromConstructedImmutableSegmentedList()
    {
        static void test<T>()
        {
            ImmutableSegmentedList<T> immutableList = ImmutableSegmentedList.Create(new T[17]);
            SegmentedList<T>? list = SegmentedCollectionsMarshal.AsSegmentedList(immutableList);
 
            AssertEx.NotNull(list);
            Assert.Equal(17, list.Count);
 
            ref T expectedRef = ref Unsafe.AsRef(in immutableList.ItemRef(0));
            ref T actualRef = ref list.GetTestAccessor().Items[0];
 
            Assert.True(Unsafe.AreSame(ref expectedRef, ref actualRef));
        }
 
        test<int>();
        test<int?>();
        test<Guid>();
        test<Guid?>();
        test<string>();
        test<CustomClass>();
        test<ManagedCustomStruct>();
        test<ManagedCustomStruct?>();
        test<UnmanagedCustomStruct>();
        test<UnmanagedCustomStruct?>();
    }
 
    [Fact]
    public void AsImmutableSegmentedHashSetFromNullSegmentedHashSet()
    {
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedHashSet<int>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedHashSet<int?>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedHashSet<Guid>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedHashSet<Guid?>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedHashSet<string>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedHashSet<CustomClass>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedHashSet<ManagedCustomStruct>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedHashSet<ManagedCustomStruct?>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedHashSet<UnmanagedCustomStruct>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedHashSet<UnmanagedCustomStruct?>(null).IsDefault);
    }
 
    [Fact]
    public void AsImmutableSegmentedHashSetFromEmptySegmentedHashSet()
    {
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedHashSet(new SegmentedHashSet<int>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedHashSet(new SegmentedHashSet<int?>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedHashSet(new SegmentedHashSet<Guid>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedHashSet(new SegmentedHashSet<Guid?>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedHashSet(new SegmentedHashSet<string>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedHashSet(new SegmentedHashSet<CustomClass>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedHashSet(new SegmentedHashSet<ManagedCustomStruct>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedHashSet(new SegmentedHashSet<ManagedCustomStruct?>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedHashSet(new SegmentedHashSet<UnmanagedCustomStruct>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedHashSet(new SegmentedHashSet<UnmanagedCustomStruct?>(0)).IsEmpty);
    }
 
    [Fact]
    public void AsImmutableSegmentedHashSetFromExistingSegmentedHashSet()
    {
        static void test<T>(IEnumerable<T> values)
        {
            SegmentedHashSet<T> set = new SegmentedHashSet<T>(values);
            ImmutableSegmentedHashSet<T> immutableHashSet = SegmentedCollectionsMarshal.AsImmutableSegmentedHashSet(set);
 
            Assert.False(immutableHashSet.IsDefault);
            Assert.Equal(17, immutableHashSet.Count);
 
            Assert.Same(set, SegmentedCollectionsMarshal.AsSegmentedHashSet(immutableHashSet));
 
            // Currently SegmentedHashSet<T> does not provide direct ref access to values, so the following tests
            // cannot be implemented in an obvious way.
 
            //ref T expectedRef = ref set.GetTestAccessor().Items[0];
            //ref T actualRef = ref Unsafe.AsRef(in immutableHashSet.ItemRef(0));
 
            //Assert.True(Unsafe.AreSame(ref expectedRef, ref actualRef));
        }
 
        test<int>(Enumerable.Range(0, 17));
        test<int?>(Enumerable.Range(0, 17).Cast<int?>());
        test<Guid>(Enumerable.Range(0, 17).Select(_ => Guid.NewGuid()));
        test<Guid?>(Enumerable.Range(0, 17).Select(_ => (Guid?)Guid.NewGuid()));
        test<string>(Enumerable.Range(0, 17).Select(_ => Guid.NewGuid().ToString()));
        test<CustomClass>(Enumerable.Range(0, 17).Select(_ => new CustomClass()));
        test<ManagedCustomStruct>(Enumerable.Range(0, 17).Select(_ => new ManagedCustomStruct() { Bar = Guid.NewGuid() }));
        test<ManagedCustomStruct?>(Enumerable.Range(0, 17).Select(_ => (ManagedCustomStruct?)new ManagedCustomStruct() { Bar = Guid.NewGuid() }));
        test<UnmanagedCustomStruct>(Enumerable.Range(0, 17).Select(_ => new UnmanagedCustomStruct() { Foo = Guid.NewGuid() }));
        test<UnmanagedCustomStruct?>(Enumerable.Range(0, 17).Select(_ => (UnmanagedCustomStruct?)new UnmanagedCustomStruct() { Foo = Guid.NewGuid() }));
    }
 
    [Fact]
    public void AsSegmentedHashSetFromDefaultImmutableSegmentedHashSet()
    {
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedHashSet<int>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedHashSet<int?>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedHashSet<Guid>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedHashSet<Guid?>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedHashSet<string>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedHashSet<CustomClass>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedHashSet<ManagedCustomStruct>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedHashSet<ManagedCustomStruct?>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedHashSet<UnmanagedCustomStruct>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedHashSet<UnmanagedCustomStruct?>(default));
    }
 
    [Fact]
    public void AsSegmentedHashSetFromEmptyImmutableSegmentedHashSet()
    {
        static void test<T>()
        {
            SegmentedHashSet<T>? set = SegmentedCollectionsMarshal.AsSegmentedHashSet(ImmutableSegmentedHashSet<T>.Empty);
 
            Assert.NotNull(set);
            Assert.Empty(set);
        }
 
        test<int>();
        test<int?>();
        test<Guid>();
        test<Guid?>();
        test<string>();
        test<CustomClass>();
        test<ManagedCustomStruct>();
        test<ManagedCustomStruct?>();
        test<UnmanagedCustomStruct>();
        test<UnmanagedCustomStruct?>();
    }
 
    [Fact]
    public void AsSegmentedHashSetFromConstructedImmutableSegmentedHashSet()
    {
        static void test<T>(IEnumerable<T> values)
        {
            ImmutableSegmentedHashSet<T> immutableHashSet = ImmutableSegmentedHashSet.CreateRange(values);
            SegmentedHashSet<T>? set = SegmentedCollectionsMarshal.AsSegmentedHashSet(immutableHashSet);
 
            AssertEx.NotNull(set);
            Assert.Equal(17, set.Count);
 
            Assert.Same(set, SegmentedCollectionsMarshal.AsSegmentedHashSet(immutableHashSet));
 
            // Currently SegmentedHashSet<T> does not provide direct ref access to values, so the following tests
            // cannot be implemented in an obvious way.
 
            //ref T expectedRef = ref Unsafe.AsRef(in immutableHashSet.ItemRef(0));
            //ref T actualRef = ref set.GetTestAccessor().Items[0];
 
            //Assert.True(Unsafe.AreSame(ref expectedRef, ref actualRef));
        }
 
        test<int>(Enumerable.Range(0, 17));
        test<int?>(Enumerable.Range(0, 17).Cast<int?>());
        test<Guid>(Enumerable.Range(0, 17).Select(_ => Guid.NewGuid()));
        test<Guid?>(Enumerable.Range(0, 17).Select(_ => (Guid?)Guid.NewGuid()));
        test<string>(Enumerable.Range(0, 17).Select(_ => Guid.NewGuid().ToString()));
        test<CustomClass>(Enumerable.Range(0, 17).Select(_ => new CustomClass()));
        test<ManagedCustomStruct>(Enumerable.Range(0, 17).Select(_ => new ManagedCustomStruct() { Bar = Guid.NewGuid() }));
        test<ManagedCustomStruct?>(Enumerable.Range(0, 17).Select(_ => (ManagedCustomStruct?)new ManagedCustomStruct() { Bar = Guid.NewGuid() }));
        test<UnmanagedCustomStruct>(Enumerable.Range(0, 17).Select(_ => new UnmanagedCustomStruct() { Foo = Guid.NewGuid() }));
        test<UnmanagedCustomStruct?>(Enumerable.Range(0, 17).Select(_ => (UnmanagedCustomStruct?)new UnmanagedCustomStruct() { Foo = Guid.NewGuid() }));
    }
 
    [Fact]
    public void AsImmutableSegmentedDictionaryFromNullSegmentedDictionary()
    {
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedDictionary<int, int>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedDictionary<int, int?>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedDictionary<Guid, Guid>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedDictionary<Guid, Guid?>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedDictionary<string, string>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedDictionary<CustomClass, CustomClass>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedDictionary<ManagedCustomStruct, ManagedCustomStruct>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedDictionary<ManagedCustomStruct, ManagedCustomStruct?>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedDictionary<UnmanagedCustomStruct, UnmanagedCustomStruct>(null).IsDefault);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedDictionary<UnmanagedCustomStruct, UnmanagedCustomStruct?>(null).IsDefault);
    }
 
    [Fact]
    public void AsImmutableSegmentedDictionaryFromEmptySegmentedDictionary()
    {
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedDictionary(new SegmentedDictionary<int, int>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedDictionary(new SegmentedDictionary<int, int?>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedDictionary(new SegmentedDictionary<Guid, Guid>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedDictionary(new SegmentedDictionary<Guid, Guid?>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedDictionary(new SegmentedDictionary<string, string>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedDictionary(new SegmentedDictionary<CustomClass, CustomClass>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedDictionary(new SegmentedDictionary<ManagedCustomStruct, ManagedCustomStruct>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedDictionary(new SegmentedDictionary<ManagedCustomStruct, ManagedCustomStruct?>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedDictionary(new SegmentedDictionary<UnmanagedCustomStruct, UnmanagedCustomStruct>(0)).IsEmpty);
        Assert.True(SegmentedCollectionsMarshal.AsImmutableSegmentedDictionary(new SegmentedDictionary<UnmanagedCustomStruct, UnmanagedCustomStruct?>(0)).IsEmpty);
    }
 
    [Fact]
    public void AsImmutableSegmentedDictionaryFromExistingSegmentedDictionary()
    {
        static void test<TValue>(Func<TValue> createValue)
        {
            SegmentedDictionary<int, TValue> dictionary = new SegmentedDictionary<int, TValue>(Enumerable.Range(0, 17).Select(x => new KeyValuePair<int, TValue>(x, createValue())));
            ImmutableSegmentedDictionary<int, TValue> immutableDictionary = SegmentedCollectionsMarshal.AsImmutableSegmentedDictionary(dictionary);
 
            Assert.False(immutableDictionary.IsDefault);
            Assert.Equal(17, immutableDictionary.Count);
 
            ref TValue expectedRef = ref SegmentedCollectionsMarshal.GetValueRefOrNullRef(dictionary, 0);
            ref TValue actualRef = ref Unsafe.AsRef(in SegmentedCollectionsMarshal.GetValueRefOrNullRef(immutableDictionary, 0));
 
            Assert.True(Unsafe.AreSame(ref expectedRef, ref actualRef));
        }
 
        test<int>(() => default);
        test<int?>(() => null);
        test<Guid>(() => default);
        test<Guid?>(() => null);
        test<string>(() => "");
        test<CustomClass>(() => new CustomClass());
        test<ManagedCustomStruct>(() => new ManagedCustomStruct());
        test<ManagedCustomStruct?>(() => new ManagedCustomStruct());
        test<UnmanagedCustomStruct>(() => new UnmanagedCustomStruct());
        test<UnmanagedCustomStruct?>(() => new UnmanagedCustomStruct());
    }
 
    [Fact]
    public void AsSegmentedDictionaryFromDefaultImmutableSegmentedDictionary()
    {
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedDictionary<int, int>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedDictionary<int, int?>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedDictionary<Guid, Guid>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedDictionary<Guid, Guid?>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedDictionary<string, string>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedDictionary<CustomClass, CustomClass>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedDictionary<ManagedCustomStruct, ManagedCustomStruct>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedDictionary<ManagedCustomStruct, ManagedCustomStruct?>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedDictionary<UnmanagedCustomStruct, UnmanagedCustomStruct>(default));
        Assert.Null(SegmentedCollectionsMarshal.AsSegmentedDictionary<UnmanagedCustomStruct, UnmanagedCustomStruct?>(default));
    }
 
    [Fact]
    public void AsSegmentedDictionaryFromEmptyImmutableSegmentedDictionary()
    {
        static void test<T>()
        {
            SegmentedDictionary<int, T>? dictionary = SegmentedCollectionsMarshal.AsSegmentedDictionary(ImmutableSegmentedDictionary<int, T>.Empty);
 
            Assert.NotNull(dictionary);
            Assert.Empty(dictionary);
        }
 
        test<int>();
        test<int?>();
        test<Guid>();
        test<Guid?>();
        test<string>();
        test<CustomClass>();
        test<ManagedCustomStruct>();
        test<ManagedCustomStruct?>();
        test<UnmanagedCustomStruct>();
        test<UnmanagedCustomStruct?>();
    }
 
    [Fact]
    public void AsSegmentedDictionaryFromConstructedImmutableSegmentedDictionary()
    {
        static void test<T>(Func<T> createValue)
        {
            ImmutableSegmentedDictionary<int, T> immutableDictionary = ImmutableSegmentedDictionary.CreateRange(Enumerable.Range(0, 17).Select(x => new KeyValuePair<int, T>(x, createValue())));
            SegmentedDictionary<int, T>? dictionary = SegmentedCollectionsMarshal.AsSegmentedDictionary(immutableDictionary);
 
            AssertEx.NotNull(dictionary);
            Assert.Equal(17, dictionary.Count);
 
            ref T expectedRef = ref Unsafe.AsRef(in SegmentedCollectionsMarshal.GetValueRefOrNullRef(immutableDictionary, 0));
            ref T actualRef = ref SegmentedCollectionsMarshal.GetValueRefOrNullRef(dictionary, 0);
 
            Assert.True(Unsafe.AreSame(ref expectedRef, ref actualRef));
        }
 
        test<int>(() => default);
        test<int?>(() => null);
        test<Guid>(() => default);
        test<Guid?>(() => null);
        test<string>(() => "");
        test<CustomClass>(() => new CustomClass());
        test<ManagedCustomStruct>(() => new ManagedCustomStruct());
        test<ManagedCustomStruct?>(() => new ManagedCustomStruct());
        test<UnmanagedCustomStruct>(() => new UnmanagedCustomStruct());
        test<UnmanagedCustomStruct?>(() => new UnmanagedCustomStruct());
    }
 
    private struct Struct
    {
        public int Value;
        public int Property { get; set; }
    }
 
    private class IntAsObject
    {
        public int Value;
        public int Property { get; set; }
    }
 
    public class CustomClass
    {
        public object? Foo;
        public Guid Bar;
    }
 
    public struct ManagedCustomStruct
    {
        public object? Foo;
        public Guid Bar;
    }
 
    public struct UnmanagedCustomStruct
    {
        public Guid Foo;
        public int Bar;
    }
}