// <auto-generated>
// This file was generated by BoltFFI. Do not edit.
// </auto-generated>
#nullable enable
using System;
{%- if class.has_streams() %}
using System.Collections.Generic;
{%- endif %}
using System.Threading;
{%- if class.has_pinned_params() || class.has_streams() %}
using System.Runtime.CompilerServices;
{%- endif %}
{%- if class.has_streams() %}
using System.Threading.Tasks;
{%- endif %}
{%- if class.needs_system_text() %}
using System.Text;
{%- endif %}
namespace {{ namespace }}
{
{{ self::summary_doc_block(class.summary_doc, " ") }} public sealed class {{ class.class_name }} : IDisposable
{
private IntPtr _handle;
// Private handle-adopting ctor; used only by chained `: this(...)` and the static factories below.
private {{ class.class_name }}(IntPtr handle)
{
_handle = handle;
}
{%- for ctor in class.constructors %}
{%- match ctor.kind %}
{%- when CSharpConstructorKind::Primary with { helper_method_name } %}
{{ self::summary_doc_block(ctor.summary_doc, " ") }} public {{ class.class_name }}({% for p in ctor.params %}{{ p.csharp_type }} {{ p.name }}{% if !loop.last %}, {% endif %}{% endfor %})
: this({{ helper_method_name }}({% for p in ctor.params %}{{ p.name }}{% if !loop.last %}, {% endif %}{% endfor %})) { }
private static IntPtr {{ helper_method_name }}({% for p in ctor.params %}{{ p.csharp_type }} {{ p.name }}{% if !loop.last %}, {% endif %}{% endfor %})
{
{%- for param in ctor.params %}
{%- if let Some(decl) = param.setup_declaration() %}
{{ decl }}
{%- endif %}
{%- endfor %}
{%- for writer in ctor.wire_writers %}
using var {{ writer.binding_name }} = new WireWriter({{ writer.size_expr }});
{%- for stmt in writer.encode_stmts %}
{{ stmt }};
{%- endfor %}
byte[] {{ writer.bytes_binding_name }} = {{ writer.binding_name }}.ToArray();
{%- endfor %}
{%- if ctor.has_pinned_params() %}
unsafe
{
{%- for param in ctor.params %}
{%- match param.kind %}
{%- when CSharpParamKind::PinnedArray with { element_type, ptr_local } %}
fixed ({{ element_type }}* {{ ptr_local }} = {{ param.name }})
{
{%- when _ %}
{%- endmatch %}
{%- endfor %}
return NativeMethods.{{ ctor.native_method_name }}({{ ctor.native_call_args() }});
{%- for param in ctor.params %}
{%- if param.is_pinned() %}
}
{%- endif %}
{%- endfor %}
}
{%- else %}
return NativeMethods.{{ ctor.native_method_name }}({{ ctor.native_call_args() }});
{%- endif %}
}
{%- when CSharpConstructorKind::StaticFactory with { name } %}
{{ self::summary_doc_block(ctor.summary_doc, " ") }} public static {{ class.class_name }} {{ name }}({% for p in ctor.params %}{{ p.csharp_type }} {{ p.name }}{% if !loop.last %}, {% endif %}{% endfor %})
{
{%- for param in ctor.params %}
{%- if let Some(decl) = param.setup_declaration() %}
{{ decl }}
{%- endif %}
{%- endfor %}
{%- for writer in ctor.wire_writers %}
using var {{ writer.binding_name }} = new WireWriter({{ writer.size_expr }});
{%- for stmt in writer.encode_stmts %}
{{ stmt }};
{%- endfor %}
byte[] {{ writer.bytes_binding_name }} = {{ writer.binding_name }}.ToArray();
{%- endfor %}
{%- if ctor.has_pinned_params() %}
unsafe
{
{%- for param in ctor.params %}
{%- match param.kind %}
{%- when CSharpParamKind::PinnedArray with { element_type, ptr_local } %}
fixed ({{ element_type }}* {{ ptr_local }} = {{ param.name }})
{
{%- when _ %}
{%- endmatch %}
{%- endfor %}
return new {{ class.class_name }}(NativeMethods.{{ ctor.native_method_name }}({{ ctor.native_call_args() }}));
{%- for param in ctor.params %}
{%- if param.is_pinned() %}
}
{%- endif %}
{%- endfor %}
}
{%- else %}
return new {{ class.class_name }}(NativeMethods.{{ ctor.native_method_name }}({{ ctor.native_call_args() }}));
{%- endif %}
}
{%- endmatch %}
{%- endfor %}
{%- for method in class.methods %}
{% include "render_csharp/class_method.txt" %}
{%- endfor %}
{%- for stream in class.streams %}
{{ self::summary_doc_block(stream.summary_doc, " ") }} /// <remarks>
/// The returned <see cref="IAsyncEnumerable{T}"/> owns the underlying
/// subscription. Disposing the owning <see cref="{{ class.class_name }}"/>
/// instance does not, by itself, end iteration - the producer simply
/// stops emitting events. Callers must either cancel the supplied
/// <see cref="CancellationToken"/> or break out of <c>await foreach</c>
/// to release the subscription.
/// </remarks>
public async IAsyncEnumerable<{{ stream.item_type }}> {{ stream.name }}([EnumeratorCancellation] CancellationToken cancellationToken = default)
{
ThrowIfDisposed();
IntPtr subscription = NativeMethods.{{ stream.subscribe_method_name }}(_handle);
if (subscription == IntPtr.Zero) yield break;
global::System.Threading.Tasks.Task<int>? _pendingWait = null;
try
{
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
while (true)
{
{{ stream.item_type }}[] _items = new {{ stream.item_type }}[BoltFFIStream.DefaultBatchSize];
int _itemCount;
UIntPtr _count;
unsafe
{
fixed ({{ stream.item_type }}* _itemsPtr = _items)
{
_count = NativeMethods.{{ stream.pop_batch_method_name }}(subscription, (IntPtr)_itemsPtr, (UIntPtr)_items.Length);
}
}
_itemCount = checked((int)(nuint)_count);
if (_itemCount == 0) break;
for (int _i = 0; _i < _itemCount; _i++)
{
cancellationToken.ThrowIfCancellationRequested();
yield return _items[_i];
}
if (_itemCount < BoltFFIStream.DefaultBatchSize) break;
}
_pendingWait = global::System.Threading.Tasks.Task.Run(
() => NativeMethods.{{ stream.wait_method_name }}(subscription, BoltFFIStream.WaitTimeoutMilliseconds),
cancellationToken);
int _waitResult = await _pendingWait.ConfigureAwait(false);
_pendingWait = null;
if (_waitResult == BoltFFIStream.WaitResultUnsubscribed) yield break;
}
}
finally
{
NativeMethods.{{ stream.unsubscribe_method_name }}(subscription);
if (_pendingWait is not null)
{
try { await _pendingWait.ConfigureAwait(false); }
catch { /* wait may have observed cancellation; ignore */ }
}
NativeMethods.{{ stream.free_method_name }}(subscription);
}
}
{%- endfor %}
internal IntPtr RawHandle => _handle;
private void ThrowIfDisposed()
{
if (_handle == IntPtr.Zero) throw new ObjectDisposedException(nameof({{ class.class_name }}));
}
public void Dispose()
{
IntPtr handle = Interlocked.Exchange(ref _handle, IntPtr.Zero);
if (handle == IntPtr.Zero) return;
NativeMethods.{{ class.native_free_method_name }}(handle);
GC.SuppressFinalize(this);
}
~{{ class.class_name }}()
{
Dispose();
}
}
}