IOneOfAccessor
IAccessor └── IOneOfAccessor └── IOneOfAccessor<Container> └── IOneOfAccessor<Container, Content>
IOneOfAccessor describes writers that access a one-of. OneOf can exist as class, struct, memory-span or stream.
/// <summary>OneOf accessor</summary>
public interface IOneOfAccessor : IAccessor, IFieldContainerAccessor, IDefaultConstructorAccessor, IConstructorAccessor, IDeconstructorAccessor, IContainerAccessor
{
/// <summary>Get assignment as index of <see cref="Fields"/>, -1 if unassiged.</summary>
IWriterTo<int> GetIndex { get; set; }
}
/// <summary>Accessor for container that has fields.</summary>
public interface IFieldContainerAccessor : IAccessor
{
/// <summary>Fields.</summary>
IContentAccessor[] Fields { get; set; }
}
IOneOfAccessor<Container> and IOneOfAccessor<Container, Content> contain accessing writers for container type Container.
/// <summary>OneOf accessor of <typeparamref name="Container"/>.</summary>
public interface IOneOfAccessor<Container> : IOneOfAccessorT, IContainerAccessor<Container>, IFieldContainerAccessor<Container>, IAccessor<Container>, IDefaultConstructorAccessor<Container>, IConstructorAccessor<Container>, IDeconstructorAccessor<Container> where Container : notnull
{
/// <summary>Get assignment as index of <see cref="Fields"/>.</summary>
new IWriterBase<Container, int> GetIndex { get; set; }
}
/// <summary>One-of accessor of <typeparamref name="Container"/> and <typeparamref name="Content"/> unifying type.</summary>
public interface IOneOfAccessor<Container, Content> : IOneOfAccessor<Container>, IOneOfAccessorOf<Content>, IConstructorAccessor<Container, (int Index, Content Value)>, IDeconstructorAccessor<Container, (int Index, Content Value)>, IFieldContainerAccessor<Container, Content> where Container : notnull { }
IOneOfVisitor and IOneOfVisitorT are visitor interfaces for IAccessorBase.Accept(IAccessorVisitor).
/// <summary>Base interface for one of visitor</summary>
public interface IOneOfVisitor : IAccessorVisitor
{
/// <summary>Try visit <paramref name="oneOfAccessor"/>.</summary>
/// <returns>true to continue visitation</returns>
bool VisitOneOfAccessor(IOneOfAccessor oneOfAccessor);
}
/// <summary>Base interface for one of visitor</summary>
public interface IOneOfVisitorT : IAccessorVisitor
{
/// <summary>Try visit <paramref name="OneOfAccessor"/>.</summary>
/// <returns>true to continue visitation</returns>
bool VisitOneOfAccessor<Container, Content>(IOneOfAccessor<Container, Content> oneOfAccessor) where Container : notnull;
}
OneOfAccessor
AccessorBase └── OneOfAccessor └── OneOfAccessor<Container> └── OneOfAccessor<Container, Content>
OneOfAccessor is implementation without specific container and content types.
IRecordAccessor accessor = new RecordAccessor()
{
Fields = Array.Empty<IContentAccessor>(),
DefaultConstructor = null!,
Constructor = null!,
Deconstructor = null!,
IsAssigned = null!,
Unassign = null!
}.SetReadOnly();
OneOfAccessor<Container> is the default implementation.
IOneOfAccessor accessor = new OneOfAccessor<OneOf>()
{
Fields = Array.Empty<IContentAccessor<OneOf>>(),
DefaultConstructor = null!,
Constructor = null!,
Deconstructor = null!,
IsAssigned = null!,
Unassign = null!
}.SetReadOnly();
OneOfAccessor<Container, Content> is implementation for specific Container and Content types.
IOneOfAccessor accessor = new OneOfAccessor<OneOf, object>()
{
Fields = Array.Empty<IContentAccessor<OneOf, object>>(),
DefaultConstructor = null!,
Constructor = null!,
Deconstructor = null!,
IsAssigned = null!,
Unassign = null!
}.SetReadOnly();
OneOfAccessor.Create(containerType) constructs IOneOfAccessor<Container> with run-time types. There are extension method a setters for each field.
IOneOfAccessor accessor =
OneOfAccessor.Create(typeof(OneOf))
.SetConstructor(null!)
.SetDeconstructor(null!)
.SetDefaultConstructor(null!)
.SetFields(Array.Empty<IContentAccessor>())
.SetIsAssigned(null!)
.SetUnassign(null!)
.SetReadOnly();
OneOfAccessor.Create(containerType, contentType) constructs IOneOfAccessor<Container, Content>.
IOneOfAccessor accessor =
OneOfAccessor.Create(typeof(OneOf), typeof(object))
.SetConstructor(null!)
.SetDeconstructor(null!)
.SetDefaultConstructor(null!)
.SetFields(Array.Empty<IContentAccessor<OneOf, object>>())
.SetIsAssigned(null!)
.SetUnassign(null!)
.SetReadOnly();
Query
AccessorRequest(target) requests for IAccessor depending on type target.
// Create service
IService service = Services.Create(NetAccessorHandlers.Instance);
// Create container target
IContainerTarget target = new NetOneOf(typeof(IMessage));
// Create request
IRequestFor<IAccessor> request = new AccessorRequest(target);
// Issue request
IOneOfAccessor<IMessage> accessor = service.GetRequired<IRequest, IOneOfAccessor<IMessage>>(request);
OneOfAccessorRequest(target) requests for IOneOfAccessor<OneOf, Element>.
// Create service
IService service = Services.Create(NetAccessorHandlers.Instance);
// Create container target
IContainerTarget target = new NetOneOf(typeof(IMessage));
// Create request
IRequestFor<IOneOfAccessor> request = new OneOfAccessorRequest(target);
// Issue request
IOneOfAccessor<IMessage> accessor = service.GetRequired<IRequest, IOneOfAccessor<IMessage>>(request);
OneOfAccessorRequest is specifically a request for specific writers. Each can be assigned with explicit customization.
// Create service
IService service = Services.Create(NetAccessorHandlers.Instance);
// Create container target
IContainerTarget target = new NetOneOf(typeof(IMessage));
// Create request
IRequestFor<IOneOfAccessor> request = new OneOfAccessorRequest
{
Constructor = new ConstructorRequest(target),
Deconstructor = new DeconstructorRequest(target),
DefaultConstructor = new DefaultConstructorRequest(target),
Fields = new ContentAccessorsRequest(target),
IsAssigned = new IsAssignedRequest(target),
Unassign = new UnassignRequest(target),
ContainerType = new ContainerTypeRequest(target),
ContentType = new ContentTypeRequest(target),
};
// Issue request
IOneOfAccessor<IMessage> accessor = service.GetRequired<IRequest, IOneOfAccessor<IMessage>>(request);
Example one-of .NET types.
[OneOf(typeof(Result), typeof(Error), typeof(NoResult))]
public interface IMessage
{
public sealed class Result : IMessage { }
public sealed class Error : IMessage { }
public sealed class NoResult : IMessage { }
}
[StructLayout(LayoutKind.Explicit)]
public struct OneOf
{
[FieldOffset(0)] public Kind Tag;
[FieldOffset(1)] public int Integer;
[FieldOffset(1)] public ushort Short;
[FieldOffset(1)] public bool Bool;
public enum Kind : byte { Integer, Short, Bool }
}
Usage
.DefaultConstructor creates a oneof with default value.
IMessage oneOf = accessor.DefaultConstructor.Read();
.Constructor creates a oneof from enumerable of elements.
IMessage oneOf = accessor.Constructor.ReadAs<(int tag, IMessage message), IMessage>((2, new IMessage.NoResult()));
.Deconstructor reads values as an enumerable.
IMessage oneOf = new IMessage.Error();
(int tag, IMessage msg) = accessor.Deconstructor.ReadAs<IMessage, (int tag, IMessage message)>(oneOf);
.Fields contains one-of option types.
IMessage oneOf = null!;
accessor.Fields[1].Writer.WriteAs<IMessage.Error, IMessage>(new IMessage.Error(), ref oneOf);
IMessage.Error result = accessor.Fields[1].Reader.ReadAs<IMessage, IMessage.Error>(oneOf);
.IsAssigned tests whether a oneof is assigned in container.
IMessage oneOf = new IMessage.Result();
bool nonNull = accessor.IsAssigned.Read(oneOf);
.Unassign removes oneof at container.
IMessage oneOf = new IMessage.Result();
accessor.Unassign.Write(default, ref oneOf);
Notes
A ref is used when accessing value-typed container.
// Create accessor
IOneOfAccessor<OneOf> accessor =
Services.Create(NetAccessorHandlers.Instance)
.GetRequiredService<IOneOfAccessor<OneOf>>();
// Create value-typed one-of on stack
OneOf oneOf = new OneOf { Tag = OneOf.Kind.Integer, Integer = 10 };
// Assign case to one-of type on stack
accessor.Fields[1].Writer.WriteAs<ushort, OneOf>((ushort)11, ref oneOf);
[StructLayout(LayoutKind.Explicit)]
public struct OneOf
{
[FieldOffset(0)] public Kind Tag;
[FieldOffset(1)] public int Integer;
[FieldOffset(1)] public ushort Short;
[FieldOffset(1)] public bool Bool;
public enum Kind : byte { Integer, Short, Bool }
}
Boxed value-types can be accessed as object.
// Create accessor
IOneOfAccessor<OneOf> accessor =
Services.Create(NetAccessorHandlers.Instance)
.GetRequiredService<IOneOfAccessor<OneOf>>();
// Create one-of in heap
object oneOf = new OneOf { Tag = OneOf.Kind.Integer, Integer = 10 };
// Assign case to box in heap
accessor.Fields[1].Writer.TypeCast<ushort, object>().Write((ushort)11, oneOf);
Full Example
Full example
using System;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using Avalanche.Accessor;
using Avalanche.DataType;
using Avalanche.Service;
using Avalanche.Utilities;
using Avalanche.Writer;
using Microsoft.Extensions.DependencyInjection;
public class oneofaccessor
{
public static void Run()
{
{
// <00>
IOneOfAccessor accessor = new OneOfAccessor()
{
Fields = Array.Empty<IContentAccessor>(),
DefaultConstructor = null!,
Constructor = null!,
Deconstructor = null!,
IsAssigned = null!,
Unassign = null!
}.SetReadOnly();
// </00>
}
{
// <01>
IOneOfAccessor accessor = new OneOfAccessor<OneOf>()
{
Fields = Array.Empty<IContentAccessor<OneOf>>(),
DefaultConstructor = null!,
Constructor = null!,
Deconstructor = null!,
IsAssigned = null!,
Unassign = null!
}.SetReadOnly();
// </01>
}
{
// <02>
IOneOfAccessor accessor = new OneOfAccessor<OneOf, object>()
{
Fields = Array.Empty<IContentAccessor<OneOf, object>>(),
DefaultConstructor = null!,
Constructor = null!,
Deconstructor = null!,
IsAssigned = null!,
Unassign = null!
}.SetReadOnly();
// </02>
}
{
// <03>
IOneOfAccessor accessor =
OneOfAccessor.Create(typeof(OneOf))
.SetConstructor(null!)
.SetDeconstructor(null!)
.SetDefaultConstructor(null!)
.SetFields(Array.Empty<IContentAccessor>())
.SetIsAssigned(null!)
.SetUnassign(null!)
.SetReadOnly();
// </03>
}
{
// <04>
IOneOfAccessor accessor =
OneOfAccessor.Create(typeof(OneOf), typeof(object))
.SetConstructor(null!)
.SetDeconstructor(null!)
.SetDefaultConstructor(null!)
.SetFields(Array.Empty<IContentAccessor<OneOf, object>>())
.SetIsAssigned(null!)
.SetUnassign(null!)
.SetReadOnly();
// </04>
}
{
// <10>
// Create service
IService service = Services.Create(NetAccessorHandlers.Instance);
// Create container target
IContainerTarget target = new NetOneOf(typeof(IMessage));
// Create request
IRequestFor<IAccessor> request = new AccessorRequest(target);
// Issue request
IOneOfAccessor<IMessage> accessor = service.GetRequired<IRequest, IOneOfAccessor<IMessage>>(request);
// </10>
}
{
// <11>
// Create service
IService service = Services.Create(NetAccessorHandlers.Instance);
// Create container target
IContainerTarget target = new NetOneOf(typeof(IMessage));
// Create request
IRequestFor<IOneOfAccessor> request = new OneOfAccessorRequest(target);
// Issue request
IOneOfAccessor<IMessage> accessor = service.GetRequired<IRequest, IOneOfAccessor<IMessage>>(request);
// </11>
}
{
// <11B>
// Create service
IService service = Services.Create(NetAccessorHandlers.Instance);
// Create container target
IContainerTarget target = new NetOneOf(typeof(IMessage), typeof(object));
// Create request
IRequestFor<IOneOfAccessor> request = new OneOfAccessorRequest(target);
// Issue request
IOneOfAccessor<IMessage> accessor = service.GetRequired<IRequest, IOneOfAccessor<IMessage, object>>(request);
// </11B>
}
{
// <12>
// Create service
IService service = Services.Create(NetAccessorHandlers.Instance);
// Create container target
IContainerTarget target = new NetOneOf(typeof(IMessage));
// Create request
IRequestFor<IOneOfAccessor> request = new OneOfAccessorRequest
{
Constructor = new ConstructorRequest(target),
Deconstructor = new DeconstructorRequest(target),
DefaultConstructor = new DefaultConstructorRequest(target),
Fields = new ContentAccessorsRequest(target),
IsAssigned = new IsAssignedRequest(target),
Unassign = new UnassignRequest(target),
ContainerType = new ContainerTypeRequest(target),
ContentType = new ContentTypeRequest(target),
};
// Issue request
IOneOfAccessor<IMessage> accessor = service.GetRequired<IRequest, IOneOfAccessor<IMessage>>(request);
// </12>
}
{
IOneOfAccessor<IMessage> accessor = Services.Create(NetAccessorHandlers.Instance).GetRequiredService<IOneOfAccessor<IMessage>>();
{
// <51>
IMessage oneOf = accessor.DefaultConstructor.Read();
// </51>
}
{
// <52>
IMessage oneOf = accessor.Constructor.ReadAs<(int tag, IMessage message), IMessage>((2, new IMessage.NoResult()));
// </52>
}
{
// <53>
IMessage oneOf = new IMessage.Error();
(int tag, IMessage msg) = accessor.Deconstructor.ReadAs<IMessage, (int tag, IMessage message)>(oneOf);
// </53>
}
{
// <54>
IMessage oneOf = null!;
accessor.Fields[1].Writer.WriteAs<IMessage.Error, IMessage>(new IMessage.Error(), ref oneOf);
IMessage.Error result = accessor.Fields[1].Reader.ReadAs<IMessage, IMessage.Error>(oneOf);
// </54>
}
{
// <62>
IMessage oneOf = new IMessage.Result();
bool nonNull = accessor.IsAssigned.Read(oneOf);
// </62>
}
{
// <63>
IMessage oneOf = new IMessage.Result();
accessor.Unassign.Write(default, ref oneOf);
// </63>
}
}
{
// <71>
// Create accessor
IOneOfAccessor<OneOf> accessor =
Services.Create(NetAccessorHandlers.Instance)
.GetRequiredService<IOneOfAccessor<OneOf>>();
// Create value-typed one-of on stack
OneOf oneOf = new OneOf { Tag = OneOf.Kind.Integer, Integer = 10 };
// Assign case to one-of type on stack
accessor.Fields[1].Writer.WriteAs<ushort, OneOf>((ushort)11, ref oneOf);
// </71>
}
{
// <72>
// Create accessor
IOneOfAccessor<OneOf> accessor =
Services.Create(NetAccessorHandlers.Instance)
.GetRequiredService<IOneOfAccessor<OneOf>>();
// Create one-of in heap
object oneOf = new OneOf { Tag = OneOf.Kind.Integer, Integer = 10 };
// Assign case to box in heap
accessor.Fields[1].Writer.TypeCast<ushort, object>().Write((ushort)11, oneOf);
// </72>
}
}
// <100>
[OneOf(typeof(Result), typeof(Error), typeof(NoResult))]
public interface IMessage
{
public sealed class Result : IMessage { }
public sealed class Error : IMessage { }
public sealed class NoResult : IMessage { }
}
// </100>
// <101>
[StructLayout(LayoutKind.Explicit)]
public struct OneOf
{
[FieldOffset(0)] public Kind Tag;
[FieldOffset(1)] public int Integer;
[FieldOffset(1)] public ushort Short;
[FieldOffset(1)] public bool Bool;
public enum Kind : byte { Integer, Short, Bool }
}
// </101>
}