File: _generated\0\LayoutSet.g.cs
Web Access
Project: src\runtime\src\native\managed\cdac\Microsoft.Diagnostics.DataContractReader.Contracts\Microsoft.Diagnostics.DataContractReader.Contracts.csproj (Microsoft.Diagnostics.DataContractReader.Contracts)
// <auto-generated/>
#nullable enable

using System;
using System.Collections.Generic;
using Microsoft.Diagnostics.DataContractReader.Contracts;

namespace Microsoft.Diagnostics.DataContractReader.Generated;

/// <summary>
/// An ordered set of type layouts resolved from multiple type info sources.
/// Field lookups iterate sources in priority order (native cdac descriptor
/// first, then managed type metadata), trying each candidate field name
/// per source. Sources are resolved lazily.
/// </summary>
internal readonly struct LayoutSet
{
    private readonly LazyLayout[] _layouts;

    public LayoutSet(LazyLayout[] layouts)
    {
        _layouts = layouts;
    }

    public ulong InstanceSize
    {
        get
        {
            foreach (LazyLayout layout in _layouts)
            {
                if (layout.Get()?.Size is uint s)
                    return s;
            }
            throw new InvalidOperationException("No layout source has a known instance size.");
        }
    }

    public bool TrySelect(TargetPointer address, out Target.TypeInfo type, out TargetPointer baseAddr, out string name, params ReadOnlySpan<string> names)
    {
        foreach (LazyLayout layout in _layouts)
        {
            if (layout.Get() is not Target.TypeInfo ti)
                continue;
            foreach (string candidate in names)
            {
                if (ti.Fields.ContainsKey(candidate))
                {
                    type = ti; baseAddr = address; name = candidate; return true;
                }
            }
        }
        type = default!; baseAddr = default; name = default!;
        return false;
    }

    public void Select(TargetPointer address, out Target.TypeInfo type, out TargetPointer baseAddr, out string name, params ReadOnlySpan<string> names)
    {
        if (!TrySelect(address, out type, out baseAddr, out name, names))
        {
            throw new InvalidOperationException(FormatMissing(names));
        }
    }

    private static string FormatMissing(ReadOnlySpan<string> names)
        => $"Field not found in any layout (names=[{string.Join(",", names.ToArray())}]).";

    public static LayoutSet Resolve(Target target, string[] names)
    {
        List<LazyLayout> layouts = new(2);

        foreach (string name in names)
        {
            if (target.TryGetTypeInfo(name, out Target.TypeInfo n))
            {
                layouts.Add(new LazyLayout(n));
                break;
            }
        }

        if (target.Contracts.TryGetContract(out IManagedTypeSource mts))
        {
            layouts.Add(new LazyLayout(() =>
            {
                foreach (string name in names)
                {
                    if (mts.TryGetTypeInfo(name, out Target.TypeInfo m))
                        return m;
                }
                return null;
            }));
        }

        return new LayoutSet(layouts.ToArray());
    }
}

/// <summary>
/// Memoized lazy holder for a single <see cref="Target.TypeInfo"/> source.
/// Constructed either with a pre-resolved value (for cheap sources) or with
/// a factory invoked on first access (for expensive sources).
/// </summary>
internal sealed class LazyLayout
{
    private Func<Target.TypeInfo?>? _factory;
    private Target.TypeInfo? _value;

    public LazyLayout(Target.TypeInfo value)
    {
        _value = value;
    }

    public LazyLayout(Func<Target.TypeInfo?> factory)
    {
        _factory = factory;
    }

    public Target.TypeInfo? Get()
    {
        if (_factory is not null)
        {
            _value = _factory();
            _factory = null;
        }
        return _value;
    }
}