Table of Contents

ISequenceOwner<T> Interface

ISequenceOwner<T> is the sequence-shaped counterpart to ISegmentOwner<T>, and follows the same idea as IMemoryOwner<T>: the interface carries the payload, and IDisposable carries the lifetime.

It exists because the sequences returned by ArrayPoolMemoryStream.GetReadOnlySequence() and ArrayPoolBufferWriter<T>.GetReadOnlySequence() are borrowed — they stay valid only while their producer lives, so the payload dies when the stream or writer is disposed. An ISequenceOwner<T> owns the buffers instead, which lets a payload be produced in one place, handed on, and released by whoever finishes with it.

Namespace

CryptoHives.Foundation.Memory.Buffers

Inheritance

IDisposableISequenceOwner<T>

Syntax

public interface ISequenceOwner<T> : IDisposable

Type Parameters

T — The element type of the sequence.

Overview

Concern Member
Data access Sequence property
Size Length, IsEmpty
Lifetime management Dispose() (from IDisposable)

There is deliberately no indexer and no re-window method, unlike ISegmentOwner<T>. A ReadOnlySequence<T> is read-only, and narrowing it is already a cheap value operation that leaves ownership untouched:

ReadOnlySequence<byte> view = owner.Sequence.Slice(start, length);

Implementations

Source What it owns Dispose behaviour
SequenceLease<T> Nothing itself — it holds the producer Disposes the producer, which frees the buffers
SegmentSequence<T> One adopted ISegmentOwner<T> Disposes the inner owner
EmptySequence<T> Nothing No-op

SequenceLease<T> is what the producers hand out, and it is the one to reach for by default.

Important

SequenceLease<T> is a struct. Using it through this interface boxes it — a measured 48 bytes — which is exactly the allocation it exists to avoid. Take the lease by its own type unless you genuinely need to treat several owner kinds uniformly.

Members

Properties

Property Type Description
Sequence ReadOnlySequence<T> The payload. Valid until the owner is disposed.
Length long Total number of elements.
IsEmpty bool Whether the owner holds nothing.

Methods

void Dispose();

Releases the underlying memory according to the concrete implementation.

Ownership Is Exclusive

There is no reference counting. A single holder is responsible for disposal, and reading Sequence afterwards is undefined — with pooled buffers the arrays behind it may already have been handed to another tenant.

If several consumers need the same payload, either keep the owner alive until the last of them is finished, or copy.

Usage

Letting a payload leave its scope

The cheap way is a SequenceLease<T>, which carries the producer along as the disposable and costs nothing:

static SequenceLease<byte> BuildPayload()
{
    var writer = ObjectPools.RentBufferWriter<byte>();
    Serialize(writer);
    return writer.LeaseSequence();
}

using SequenceLease<byte> payload = BuildPayload();
Process(payload.Sequence);

Note the producer is deliberately not disposed inside BuildPayload — the lease owns it now, and disposing it there would release the very buffers the payload is made of.

Reading through a Stream API

ReadOnlySequenceMemoryStream wraps a sequence as a readable Stream, reading the buffers in place rather than copying them, and leaves ownership where it is:

using SequenceLease<byte> payload = stream.LeaseSequence();
using var reader = new ReadOnlySequenceMemoryStream(payload.Sequence);

await client.UploadAsync(reader);

Feeding the cryptography package

The hash algorithms accept a ReadOnlySequence<byte> directly, so a multi-segment payload is hashed without ever being flattened:

using SequenceLease<byte> payload = writer.LeaseSequence();
byte[] digest = Blake3.HashData(payload.Sequence);

Composing with segment ownership

Any ISegmentOwner<T> becomes a sequence owner through SegmentSequence<T>, so code written against ISequenceOwner<T> works with every segment strategy without caring which is underneath:

ISegmentOwner<byte> segment = PooledSegment<byte>.Rent(1024);
using ISequenceOwner<byte> owner = SegmentSequence<byte>.Create(segment);

Thread Safety

Instances are not thread-safe. The intended pattern is single-owner, short-lived, scoped with using.

See Also


© 2026 The Keepers of the CryptoHives