using System.Runtime.CompilerServices;

namespace AyCode.Core.Serializers.Binaries;

/// <summary>
/// Internal value-type adapter wrapping an <see cref="AsyncPipeReaderInput"/> for the
/// <see cref="AcBinaryDeserializer"/>'s generic <c>DeserializeSequence&lt;TInput&gt;</c> path.
///
/// <para><b>Why this exists</b>: the deserializer's generic infrastructure
/// (<c>DeserializeSequence&lt;TInput&gt;</c>, <c>TypeReaderTable&lt;TInput&gt;</c>,
/// <c>DeserializationContextPool&lt;TInput&gt;</c>, and 14+ chained generic methods) constrains
/// <c>TInput</c> to <c>struct, IBinaryInputBase</c> for JIT specialization (eliminates virtual
/// dispatch in the rare-path <see cref="IBinaryInputBase.TryAdvanceSegment"/> calls).
/// <see cref="AsyncPipeReaderInput"/> is intentionally a class (per ADR-0003 — sliding-window
/// buffer state cannot live in a struct due to copy semantics during interface-method
/// dispatch). This adapter bridges the two: a stack-allocated value-type wrapping the class
/// reference, satisfying the constraint with zero heap cost.</para>
///
/// <para><b>Not user-facing API</b>: callers use the public
/// <c>AcBinaryDeserializer.Deserialize&lt;T&gt;(AsyncPipeReaderInput, ...)</c> overloads which
/// construct the adapter internally. The adapter is <c>internal</c> — visible only within the
/// <c>AyCode.Core</c> assembly.</para>
///
/// <para><b>Per-call allocation</b>: zero heap. The adapter is a <c>readonly struct</c> living
/// on the stack; the only heap allocation per <c>Deserialize</c> call is the user's
/// <see cref="AsyncPipeReaderInput"/> instance (created once per streaming session, reused
/// across all bytes of the message via sliding-window cycling).</para>
///
/// <para><b>Why not relax the deserializer's struct constraint?</b> 16+ generic declarations
/// rely on it (<c>DeserializeSequence</c>, <c>TypeReaderTable</c>,
/// <c>DeserializationContextPool</c> chain). Relaxing would require a wide refactor with risk
/// to the existing perf-critical struct paths (<c>ArrayBinaryInput</c>,
/// <c>SequenceBinaryInput</c>). The ~2 ns per call savings is sub-picosecond per byte at
/// typical chunk sizes — not worth the blast radius.</para>
/// </summary>
internal readonly struct AsyncPipeReaderInputAdapter : IBinaryInputBase
{
    /// <summary>
    /// Streaming input — chunks arrive over time via <see cref="AsyncPipeReaderInput.Feed"/>; the read path
    /// must block / advance on chunk-arrival. JIT-constant <c>false</c> → <c>EnsureAvailable</c> bounds-check
    /// + <see cref="TryAdvanceSegment"/> kept (essential for streaming-handoff).
    /// </summary>
    public static bool IsTrustedSingleSegment => false;

    private readonly AsyncPipeReaderInput _input;

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public AsyncPipeReaderInputAdapter(AsyncPipeReaderInput input) => _input = input;

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public void Initialize(out byte[] buffer, out int position, out int bufferLength)
        => _input.Initialize(out buffer, out position, out bufferLength);

    [MethodImpl(MethodImplOptions.NoInlining)]
    public bool TryAdvanceSegment(ref byte[] buffer, ref int position, ref int bufferLength, int needed)
        => _input.TryAdvanceSegment(ref buffer, ref position, ref bufferLength, needed);

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public void Release() => _input.Release();
}
