using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using ZeroDDS.Core;
using ZeroDDS.Domain;
using ZeroDDS.Topic;
namespace ZeroDDS.Sub;
public enum CftFieldKind : uint
{
Bool = 0,
Int32 = 1,
Int64 = 2,
Float32 = 3,
Float64 = 4,
String = 5,
}
public readonly record struct CftField(string Name, CftFieldKind Kind);
public sealed class ContentFilteredTopic<T> : IDisposable
{
private IntPtr _handle;
private readonly IntPtr _participant;
private readonly ITopicTraits<T> _traits;
private readonly string _name;
private readonly string _filterExpression;
private bool _disposed;
public IntPtr Handle => _handle;
public string FilterExpression => _filterExpression;
public string Name => _name;
internal ITopicTraits<T> Traits => _traits;
public ContentFilteredTopic(DomainParticipant dp, string name, Topic<T> related,
string filterExpression, IReadOnlyList<string>? parameters,
IReadOnlyList<CftField> schema)
{
_participant = dp.Handle;
_traits = related.Traits;
_name = name;
_filterExpression = filterExpression;
IntPtr paramArr = IntPtr.Zero;
var allocated = new List<IntPtr>();
try
{
UIntPtr paramCount = UIntPtr.Zero;
if (parameters is { Count: > 0 })
{
paramArr = Marshal.AllocHGlobal(IntPtr.Size * parameters.Count);
allocated.Add(paramArr);
for (int i = 0; i < parameters.Count; i++)
{
IntPtr s = Marshal.StringToHGlobalAnsi(parameters[i] ?? string.Empty);
allocated.Add(s);
Marshal.WriteIntPtr(paramArr, i * IntPtr.Size, s);
}
paramCount = (UIntPtr)parameters.Count;
}
_handle = Native.DpCreateContentFilteredTopic(_participant, name,
related.Handle, filterExpression, paramArr, paramCount);
if (_handle == IntPtr.Zero)
throw new DdsError("ContentFilteredTopic::create failed");
}
finally
{
foreach (var p in allocated) Marshal.FreeHGlobal(p);
}
if (schema is { Count: > 0 })
SetSchema(schema);
}
private void SetSchema(IReadOnlyList<CftField> schema)
{
IntPtr namesArr = Marshal.AllocHGlobal(IntPtr.Size * schema.Count);
var allocated = new List<IntPtr> { namesArr };
uint[] kinds = new uint[schema.Count];
try
{
for (int i = 0; i < schema.Count; i++)
{
IntPtr s = Marshal.StringToHGlobalAnsi(schema[i].Name);
allocated.Add(s);
Marshal.WriteIntPtr(namesArr, i * IntPtr.Size, s);
kinds[i] = (uint)schema[i].Kind;
}
unsafe
{
fixed (uint* k = kinds)
{
StatusCheck.Check(
Native.CftSetSchema(_handle, namesArr, (IntPtr)k, (UIntPtr)schema.Count),
"ContentFilteredTopic::SetSchema");
}
}
}
finally
{
foreach (var p in allocated) Marshal.FreeHGlobal(p);
}
}
public void Dispose()
{
if (_disposed) return;
_disposed = true;
if (_handle != IntPtr.Zero && _participant != IntPtr.Zero)
{
Native.DpDeleteContentFilteredTopic(_participant, _handle);
_handle = IntPtr.Zero;
}
GC.SuppressFinalize(this);
}
~ContentFilteredTopic() { Dispose(); }
}