diff --git a/Capnp.Net.Runtime/DeserializerState.cs b/Capnp.Net.Runtime/DeserializerState.cs
index eaa24f9..4c94030 100644
--- a/Capnp.Net.Runtime/DeserializerState.cs
+++ b/Capnp.Net.Runtime/DeserializerState.cs
@@ -642,6 +642,31 @@ namespace Capnp
return cons(StructReadPointer(index));
}
+ ///
+ /// Convenience method. Given this state represents a struct, determines if a field is non-null.
+ ///
+ /// index within this struct's pointer table
+ /// true if the field is non-null, false otherwise
+ /// negative or too large index
+ /// state does not represent a struct, invalid pointer,
+ /// non-struct pointer
+ public bool IsStructFieldNonNull(int index)
+ {
+ if (Kind != ObjectKind.Struct && Kind != ObjectKind.Nil)
+ {
+ throw new DeserializationException("This is not a struct");
+ }
+
+ if (index < 0 || index >= StructPtrCount)
+ {
+ throw new IndexOutOfRangeException($"Invalid index {index}. Must be [0, {StructPtrCount}).");
+ }
+
+ var pointerOffset = index + StructDataCount;
+ WirePointer pointer = CurrentSegment[Offset + pointerOffset];
+ return !pointer.IsNull;
+ }
+
///
/// Given this state represents a capability, returns its index into the capability table.
///
diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs b/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs
index ac83045..a073f18 100644
--- a/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs
+++ b/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs
@@ -325,24 +325,42 @@ namespace Capnproto_test.Capnp.Test
public string TextField => ctx.ReadText(0, null);
public IReadOnlyList DataField => ctx.ReadList(1).CastByte();
public Capnproto_test.Capnp.Test.TestAllTypes.READER StructField => ctx.ReadStruct(2, Capnproto_test.Capnp.Test.TestAllTypes.READER.create);
+ public bool HasStructField => ctx.IsStructFieldNonNull(2);
public Capnproto_test.Capnp.Test.TestEnum EnumField => (Capnproto_test.Capnp.Test.TestEnum)ctx.ReadDataUShort(288UL, (ushort)0);
public int VoidList => ctx.ReadList(3).Count;
+ public bool HasVoidList => ctx.IsStructFieldNonNull(3);
public IReadOnlyList BoolList => ctx.ReadList(4).CastBool();
+ public bool HasBoolList => ctx.IsStructFieldNonNull(4);
public IReadOnlyList Int8List => ctx.ReadList(5).CastSByte();
+ public bool HasInt8List => ctx.IsStructFieldNonNull(5);
public IReadOnlyList Int16List => ctx.ReadList(6).CastShort();
+ public bool HasInt16List => ctx.IsStructFieldNonNull(6);
public IReadOnlyList Int32List => ctx.ReadList(7).CastInt();
+ public bool HasInt32List => ctx.IsStructFieldNonNull(7);
public IReadOnlyList Int64List => ctx.ReadList(8).CastLong();
+ public bool HasInt64List => ctx.IsStructFieldNonNull(8);
public IReadOnlyList UInt8List => ctx.ReadList(9).CastByte();
+ public bool HasUInt8List => ctx.IsStructFieldNonNull(9);
public IReadOnlyList UInt16List => ctx.ReadList(10).CastUShort();
+ public bool HasUInt16List => ctx.IsStructFieldNonNull(10);
public IReadOnlyList UInt32List => ctx.ReadList(11).CastUInt();
+ public bool HasUInt32List => ctx.IsStructFieldNonNull(11);
public IReadOnlyList UInt64List => ctx.ReadList(12).CastULong();
+ public bool HasUInt64List => ctx.IsStructFieldNonNull(12);
public IReadOnlyList Float32List => ctx.ReadList(13).CastFloat();
+ public bool HasFloat32List => ctx.IsStructFieldNonNull(13);
public IReadOnlyList Float64List => ctx.ReadList(14).CastDouble();
+ public bool HasFloat64List => ctx.IsStructFieldNonNull(14);
public IReadOnlyList TextList => ctx.ReadList(15).CastText2();
+ public bool HasTextList => ctx.IsStructFieldNonNull(15);
public IReadOnlyList> DataList => ctx.ReadList(16).CastData();
+ public bool HasDataList => ctx.IsStructFieldNonNull(16);
public IReadOnlyList StructList => ctx.ReadList(17).Cast(Capnproto_test.Capnp.Test.TestAllTypes.READER.create);
+ public bool HasStructList => ctx.IsStructFieldNonNull(17);
public IReadOnlyList EnumList => ctx.ReadList(18).CastEnums(_0 => (Capnproto_test.Capnp.Test.TestEnum)_0);
+ public bool HasEnumList => ctx.IsStructFieldNonNull(18);
public int InterfaceList => ctx.ReadList(19).Count;
+ public bool HasInterfaceList => ctx.IsStructFieldNonNull(19);
}
public class WRITER : SerializerState
@@ -897,24 +915,42 @@ namespace Capnproto_test.Capnp.Test
public string TextField => ctx.ReadText(0, "foo");
public IReadOnlyList DataField => ctx.ReadList(1).CastByte();
public Capnproto_test.Capnp.Test.TestAllTypes.READER StructField => ctx.ReadStruct(2, Capnproto_test.Capnp.Test.TestAllTypes.READER.create);
+ public bool HasStructField => ctx.IsStructFieldNonNull(2);
public Capnproto_test.Capnp.Test.TestEnum EnumField => (Capnproto_test.Capnp.Test.TestEnum)ctx.ReadDataUShort(288UL, (ushort)5);
public int VoidList => ctx.ReadList(3).Count;
+ public bool HasVoidList => ctx.IsStructFieldNonNull(3);
public IReadOnlyList BoolList => ctx.ReadList(4).CastBool();
+ public bool HasBoolList => ctx.IsStructFieldNonNull(4);
public IReadOnlyList Int8List => ctx.ReadList(5).CastSByte();
+ public bool HasInt8List => ctx.IsStructFieldNonNull(5);
public IReadOnlyList Int16List => ctx.ReadList(6).CastShort();
+ public bool HasInt16List => ctx.IsStructFieldNonNull(6);
public IReadOnlyList Int32List => ctx.ReadList(7).CastInt();
+ public bool HasInt32List => ctx.IsStructFieldNonNull(7);
public IReadOnlyList Int64List => ctx.ReadList(8).CastLong();
+ public bool HasInt64List => ctx.IsStructFieldNonNull(8);
public IReadOnlyList UInt8List => ctx.ReadList(9).CastByte();
+ public bool HasUInt8List => ctx.IsStructFieldNonNull(9);
public IReadOnlyList UInt16List => ctx.ReadList(10).CastUShort();
+ public bool HasUInt16List => ctx.IsStructFieldNonNull(10);
public IReadOnlyList UInt32List => ctx.ReadList(11).CastUInt();
+ public bool HasUInt32List => ctx.IsStructFieldNonNull(11);
public IReadOnlyList UInt64List => ctx.ReadList(12).CastULong();
+ public bool HasUInt64List => ctx.IsStructFieldNonNull(12);
public IReadOnlyList Float32List => ctx.ReadList(13).CastFloat();
+ public bool HasFloat32List => ctx.IsStructFieldNonNull(13);
public IReadOnlyList Float64List => ctx.ReadList(14).CastDouble();
+ public bool HasFloat64List => ctx.IsStructFieldNonNull(14);
public IReadOnlyList TextList => ctx.ReadList(15).CastText2();
+ public bool HasTextList => ctx.IsStructFieldNonNull(15);
public IReadOnlyList> DataList => ctx.ReadList(16).CastData();
+ public bool HasDataList => ctx.IsStructFieldNonNull(16);
public IReadOnlyList StructList => ctx.ReadList(17).Cast(Capnproto_test.Capnp.Test.TestAllTypes.READER.create);
+ public bool HasStructList => ctx.IsStructFieldNonNull(17);
public IReadOnlyList EnumList => ctx.ReadList(18).CastEnums(_0 => (Capnproto_test.Capnp.Test.TestEnum)_0);
+ public bool HasEnumList => ctx.IsStructFieldNonNull(18);
public int InterfaceList => ctx.ReadList(19).Count;
+ public bool HasInterfaceList => ctx.IsStructFieldNonNull(19);
}
public class WRITER : SerializerState
@@ -4868,9 +4904,13 @@ namespace Capnproto_test.Capnp.Test
public static implicit operator DeserializerState(READER reader) => reader.ctx;
public static implicit operator READER(DeserializerState ctx) => new READER(ctx);
public Capnproto_test.Capnp.Test.TestUnion.READER S16s8s64s8Set => ctx.ReadStruct(0, Capnproto_test.Capnp.Test.TestUnion.READER.create);
+ public bool HasS16s8s64s8Set => ctx.IsStructFieldNonNull(0);
public Capnproto_test.Capnp.Test.TestUnion.READER S0sps1s32Set => ctx.ReadStruct(1, Capnproto_test.Capnp.Test.TestUnion.READER.create);
+ public bool HasS0sps1s32Set => ctx.IsStructFieldNonNull(1);
public Capnproto_test.Capnp.Test.TestUnnamedUnion.READER Unnamed1 => ctx.ReadStruct(2, Capnproto_test.Capnp.Test.TestUnnamedUnion.READER.create);
+ public bool HasUnnamed1 => ctx.IsStructFieldNonNull(2);
public Capnproto_test.Capnp.Test.TestUnnamedUnion.READER Unnamed2 => ctx.ReadStruct(3, Capnproto_test.Capnp.Test.TestUnnamedUnion.READER.create);
+ public bool HasUnnamed2 => ctx.IsStructFieldNonNull(3);
}
public class WRITER : SerializerState
@@ -4967,6 +5007,7 @@ namespace Capnproto_test.Capnp.Test
public static implicit operator DeserializerState(READER reader) => reader.ctx;
public static implicit operator READER(DeserializerState ctx) => new READER(ctx);
public Capnproto_test.Capnp.Test.TestNestedTypes.NestedStruct.READER TheNestedStruct => ctx.ReadStruct(0, Capnproto_test.Capnp.Test.TestNestedTypes.NestedStruct.READER.create);
+ public bool HasTheNestedStruct => ctx.IsStructFieldNonNull(0);
public Capnproto_test.Capnp.Test.TestNestedTypes.NestedEnum OuterNestedEnum => (Capnproto_test.Capnp.Test.TestNestedTypes.NestedEnum)ctx.ReadDataUShort(0UL, (ushort)1);
public Capnproto_test.Capnp.Test.TestNestedTypes.NestedStruct.NestedEnum InnerNestedEnum => (Capnproto_test.Capnp.Test.TestNestedTypes.NestedStruct.NestedEnum)ctx.ReadDataUShort(16UL, (ushort)2);
}
@@ -5282,15 +5323,25 @@ namespace Capnproto_test.Capnp.Test
public static implicit operator DeserializerState(READER reader) => reader.ctx;
public static implicit operator READER(DeserializerState ctx) => new READER(ctx);
public IReadOnlyList List0 => ctx.ReadList(0).Cast(Capnproto_test.Capnp.Test.TestLists.Struct0.READER.create);
+ public bool HasList0 => ctx.IsStructFieldNonNull(0);
public IReadOnlyList List1 => ctx.ReadList(1).Cast(Capnproto_test.Capnp.Test.TestLists.Struct1.READER.create);
+ public bool HasList1 => ctx.IsStructFieldNonNull(1);
public IReadOnlyList List8 => ctx.ReadList(2).Cast(Capnproto_test.Capnp.Test.TestLists.Struct8.READER.create);
+ public bool HasList8 => ctx.IsStructFieldNonNull(2);
public IReadOnlyList List16 => ctx.ReadList(3).Cast(Capnproto_test.Capnp.Test.TestLists.Struct16.READER.create);
+ public bool HasList16 => ctx.IsStructFieldNonNull(3);
public IReadOnlyList List32 => ctx.ReadList(4).Cast(Capnproto_test.Capnp.Test.TestLists.Struct32.READER.create);
+ public bool HasList32 => ctx.IsStructFieldNonNull(4);
public IReadOnlyList List64 => ctx.ReadList(5).Cast(Capnproto_test.Capnp.Test.TestLists.Struct64.READER.create);
+ public bool HasList64 => ctx.IsStructFieldNonNull(5);
public IReadOnlyList ListP => ctx.ReadList(6).Cast(Capnproto_test.Capnp.Test.TestLists.StructP.READER.create);
+ public bool HasListP => ctx.IsStructFieldNonNull(6);
public IReadOnlyList> Int32ListList => ctx.ReadList(7).Cast(_0 => _0.RequireList().CastInt());
+ public bool HasInt32ListList => ctx.IsStructFieldNonNull(7);
public IReadOnlyList> TextListList => ctx.ReadList(8).Cast(_0 => _0.RequireList().CastText2());
+ public bool HasTextListList => ctx.IsStructFieldNonNull(8);
public IReadOnlyList> StructListList => ctx.ReadList(9).Cast(_0 => _0.RequireList().Cast(Capnproto_test.Capnp.Test.TestAllTypes.READER.create));
+ public bool HasStructListList => ctx.IsStructFieldNonNull(9);
}
public class WRITER : SerializerState
@@ -6436,6 +6487,7 @@ namespace Capnproto_test.Capnp.Test
public static implicit operator DeserializerState(READER reader) => reader.ctx;
public static implicit operator READER(DeserializerState ctx) => new READER(ctx);
public Capnproto_test.Capnp.Test.TestLists.READER Lists => ctx.ReadStruct(0, Capnproto_test.Capnp.Test.TestLists.READER.create);
+ public bool HasLists => ctx.IsStructFieldNonNull(0);
}
public class WRITER : SerializerState
@@ -6696,6 +6748,7 @@ namespace Capnproto_test.Capnp.Test
public WHICH which => (WHICH)ctx.ReadDataUShort(48U, (ushort)0);
public string Qux => which == WHICH.Qux ? ctx.ReadText(1, null) : default;
public IReadOnlyList Corge => which == WHICH.Corge ? ctx.ReadList(1).CastInt() : default;
+ public bool HasCorge => ctx.IsStructFieldNonNull(1);
public float Grault => which == WHICH.Grault ? ctx.ReadDataFloat(64UL, 0F) : default;
}
@@ -6857,6 +6910,7 @@ namespace Capnproto_test.Capnp.Test
public WHICH which => (WHICH)ctx.ReadDataUShort(96U, (ushort)0);
public string Qux => which == WHICH.Qux ? ctx.ReadText(2, null) : default;
public IReadOnlyList Corge => which == WHICH.Corge ? ctx.ReadList(2).CastInt() : default;
+ public bool HasCorge => ctx.IsStructFieldNonNull(2);
public float Grault => which == WHICH.Grault ? ctx.ReadDataFloat(128UL, 0F) : default;
}
@@ -6954,6 +7008,7 @@ namespace Capnproto_test.Capnp.Test
public long Old1 => ctx.ReadDataLong(0UL, 0L);
public string Old2 => ctx.ReadText(0, null);
public Capnproto_test.Capnp.Test.TestOldVersion.READER Old3 => ctx.ReadStruct(1, Capnproto_test.Capnp.Test.TestOldVersion.READER.create);
+ public bool HasOld3 => ctx.IsStructFieldNonNull(1);
}
public class WRITER : SerializerState
@@ -7062,6 +7117,7 @@ namespace Capnproto_test.Capnp.Test
public long Old1 => ctx.ReadDataLong(0UL, 0L);
public string Old2 => ctx.ReadText(0, null);
public Capnproto_test.Capnp.Test.TestNewVersion.READER Old3 => ctx.ReadStruct(1, Capnproto_test.Capnp.Test.TestNewVersion.READER.create);
+ public bool HasOld3 => ctx.IsStructFieldNonNull(1);
public long New1 => ctx.ReadDataLong(64UL, 987L);
public string New2 => ctx.ReadText(2, "baz");
}
@@ -7633,7 +7689,9 @@ namespace Capnproto_test.Capnp.Test
public static implicit operator READER(DeserializerState ctx) => new READER(ctx);
public WHICH which => (WHICH)ctx.ReadDataUShort(0U, (ushort)0);
public Capnproto_test.Capnp.Test.TestStructUnion.SomeStruct.READER Struct => which == WHICH.Struct ? ctx.ReadStruct(0, Capnproto_test.Capnp.Test.TestStructUnion.SomeStruct.READER.create) : default;
+ public bool HasStruct => ctx.IsStructFieldNonNull(0);
public Capnproto_test.Capnp.Test.TestAnyPointer.READER Object => which == WHICH.Object ? ctx.ReadStruct(0, Capnproto_test.Capnp.Test.TestAnyPointer.READER.create) : default;
+ public bool HasObject => ctx.IsStructFieldNonNull(0);
}
public class WRITER : SerializerState
@@ -7790,6 +7848,7 @@ namespace Capnproto_test.Capnp.Test
public static implicit operator READER(DeserializerState ctx) => new READER(ctx);
public string SomeText => ctx.ReadText(0, null);
public IReadOnlyList StructList => ctx.ReadList(1).Cast(Capnproto_test.Capnp.Test.TestPrintInlineStructs.InlineStruct.READER.create);
+ public bool HasStructList => ctx.IsStructFieldNonNull(1);
}
public class WRITER : SerializerState
@@ -8084,8 +8143,10 @@ namespace Capnproto_test.Capnp.Test
public WHICH which => (WHICH)ctx.ReadDataUShort(0U, (ushort)0);
public DeserializerState Foo => ctx.StructReadPointer(0);
public Capnproto_test.Capnp.Test.TestGenerics.READER Rev => ctx.ReadStruct(1, Capnproto_test.Capnp.Test.TestGenerics.READER.create);
+ public bool HasRev => ctx.IsStructFieldNonNull(1);
public ug.READER Ug => which == WHICH.Ug ? new ug.READER(ctx) : default;
public IReadOnlyList.Inner.READER> List => ctx.ReadList(2).Cast(Capnproto_test.Capnp.Test.TestGenerics.Inner.READER.create);
+ public bool HasList => ctx.IsStructFieldNonNull(2);
}
public class WRITER : SerializerState
@@ -8328,7 +8389,9 @@ namespace Capnproto_test.Capnp.Test
public DeserializerState Bar => ctx.StructReadPointer(0);
public DeserializerState Baz => ctx.StructReadPointer(1);
public Capnproto_test.Capnp.Test.TestGenerics.Inner.READER InnerBound => ctx.ReadStruct(2, Capnproto_test.Capnp.Test.TestGenerics.Inner.READER.create);
+ public bool HasInnerBound => ctx.IsStructFieldNonNull(2);
public Capnproto_test.Capnp.Test.TestGenerics.Inner.READER InnerUnbound => ctx.ReadStruct(3, Capnproto_test.Capnp.Test.TestGenerics.Inner.READER.create);
+ public bool HasInnerUnbound => ctx.IsStructFieldNonNull(3);
}
public class WRITER : SerializerState
@@ -8713,6 +8776,7 @@ namespace Capnproto_test.Capnp.Test
public static implicit operator READER(DeserializerState ctx) => new READER(ctx);
public DeserializerState Qux => ctx.StructReadPointer(0);
public Capnproto_test.Capnp.Test.TestGenerics.READER Gen => ctx.ReadStruct(1, Capnproto_test.Capnp.Test.TestGenerics.READER.create);
+ public bool HasGen => ctx.IsStructFieldNonNull(1);
}
public class WRITER : SerializerState
@@ -8821,9 +8885,13 @@ namespace Capnproto_test.Capnp.Test
public static implicit operator READER(DeserializerState ctx) => new READER(ctx);
public DeserializerState Foo => ctx.StructReadPointer(0);
public Capnproto_test.Capnp.Test.TestGenerics.Inner.READER Inner => ctx.ReadStruct(1, Capnproto_test.Capnp.Test.TestGenerics.Inner.READER.create);
+ public bool HasInner => ctx.IsStructFieldNonNull(1);
public Capnproto_test.Capnp.Test.TestGenerics.Inner2