using System;
using System.Runtime.InteropServices;
using ZeroDDS.Core;
using ZeroDDS.Domain;
namespace ZeroDDS.Topic;
public interface ITopicTraits<T>
{
string TypeName { get; }
byte[] Encode(T value);
T Decode(ReadOnlySpan<byte> bytes);
}
public sealed class ByteSeqTraits : ITopicTraits<byte[]>
{
public string TypeName => "DDS::Bytes";
public byte[] Encode(byte[] v) => v;
public byte[] Decode(ReadOnlySpan<byte> bytes) => bytes.ToArray();
}
public sealed class StringTraits : ITopicTraits<string>
{
public string TypeName => "DDS::String";
public byte[] Encode(string v) => System.Text.Encoding.UTF8.GetBytes(v);
public string Decode(ReadOnlySpan<byte> bytes)
{
return System.Text.Encoding.UTF8.GetString(bytes);
}
}
public class TopicDescription
{
protected internal IntPtr Handle;
internal TopicDescription(IntPtr handle) { Handle = handle; }
public string Name
{
get
{
if (Handle == IntPtr.Zero) return "";
var raw = Native.TopicGetName(Handle);
if (raw == IntPtr.Zero) return "";
try
{
return Marshal.PtrToStringAnsi(raw) ?? "";
}
finally
{
Native.StringFree(raw);
}
}
}
public string TypeName
{
get
{
if (Handle == IntPtr.Zero) return "";
var raw = Native.TopicGetTypeName(Handle);
if (raw == IntPtr.Zero) return "";
try
{
return Marshal.PtrToStringAnsi(raw) ?? "";
}
finally
{
Native.StringFree(raw);
}
}
}
}
public sealed class Topic<T> : TopicDescription, IDisposable
{
private readonly IntPtr _participant;
private readonly ITopicTraits<T> _traits;
private bool _disposed;
public Topic(DomainParticipant dp, string name, ITopicTraits<T> traits)
: base(Native.DpCreateTopic(dp.Handle, name, traits.TypeName, IntPtr.Zero))
{
if (Handle == IntPtr.Zero)
throw new DdsError("Topic::create failed");
_participant = dp.Handle;
_traits = traits;
}
public Topic(DomainParticipant dp, string name, ITopicTraits<T> traits,
ZeroDDS.Qos.TopicQos qos)
: base(IntPtr.Zero)
{
using var scope = new ZeroDDS.QosBridge.NativeQosScope();
var native = ZeroDDS.QosBridge.QosBridge.ToNative(qos, scope);
unsafe
{
Handle = Native.DpCreateTopic(dp.Handle, name, traits.TypeName, (IntPtr)(&native));
}
if (Handle == IntPtr.Zero)
throw new DdsError("Topic::create with QoS failed");
_participant = dp.Handle;
_traits = traits;
}
public ITopicTraits<T> Traits => _traits;
public void Dispose()
{
if (_disposed) return;
_disposed = true;
if (Handle != IntPtr.Zero && _participant != IntPtr.Zero)
{
Native.DpDeleteTopic(_participant, Handle);
Handle = IntPtr.Zero;
}
GC.SuppressFinalize(this);
}
~Topic() { Dispose(); }
}