diff --git a/MEOS.NET.Tests/CatalogValueTypeTests.cs b/MEOS.NET.Tests/CatalogValueTypeTests.cs
new file mode 100644
index 0000000..0f4ceab
--- /dev/null
+++ b/MEOS.NET.Tests/CatalogValueTypeTests.cs
@@ -0,0 +1,49 @@
+using MEOS.NET.Enums;
+using MEOS.NET.Structures;
+using MEOS.NET.Types;
+
+namespace MEOS.NET.Tests
+{
+ ///
+ /// Whatever the wrapper already states as a C# value — an enum the catalog
+ /// names, a scalar behind a MEOS typedef, a struct carried by value — the
+ /// object layer hands on as that value.
+ ///
+ [TestClass]
+ public class CatalogValueTypeTests : MeosTest
+ {
+ [TestMethod]
+ public void AnEnumArgumentIsTheEnumTheCatalogNames()
+ {
+ TJsonb temp = (TJsonb)TJsonb.In(
+ "[{\"a\": [1, 2]}@2024-12-06, {\"a\": [1, 2]}@2024-12-08]")!;
+
+ Temporal? first = temp.ArrayElement(0, true, NullHandleType.NullJsonNull);
+
+ Assert.IsNotNull(first);
+ }
+
+ [TestMethod]
+ public void AScalarBehindATypedefComesBackAsThatScalar()
+ {
+ Geo point = Geo.FromText("POINT(1 1)", 4326)!;
+
+ ulong cell = point.ToS2cellCell(10);
+
+ Assert.AreNotEqual(0UL, cell);
+ }
+
+ [TestMethod]
+ public void AStructReturnedByValueComesBackAsTheStruct()
+ {
+ TPoint trip = (TPoint)TGeomPoint.In(
+ "[POINT(0 0)@2024-12-06, POINT(2 2)@2024-12-08]")!;
+ STBox bounds = STBox.In("STBOX X((-1,-1),(3,3))")!;
+
+ MvtGeom mvt = trip.AsMvtgeom(bounds, 4096, 0, true);
+
+ Assert.AreNotEqual(IntPtr.Zero, mvt.geom);
+ Assert.IsTrue(mvt.count > 0);
+ }
+ }
+}
diff --git a/MEOS.NET/Functions/Meos.Native.g.cs b/MEOS.NET/Functions/Meos.Native.g.cs
index fea9327..6b22b0d 100644
--- a/MEOS.NET/Functions/Meos.Native.g.cs
+++ b/MEOS.NET/Functions/Meos.Native.g.cs
@@ -9213,6 +9213,24 @@ private static partial class Native
[LibraryImport(DllPath, EntryPoint = "geo_edge_ctx_make", StringMarshalling = StringMarshalling.Utf8)]
internal static partial IntPtr GeoEdgeCtxMake(IntPtr gs);
+ [LibraryImport(DllPath, EntryPoint = "geo_is_planar_linear", StringMarshalling = StringMarshalling.Utf8)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool GeoIsPlanarLinear(IntPtr gs);
+
+ [LibraryImport(DllPath, EntryPoint = "geo_is_point_set", StringMarshalling = StringMarshalling.Utf8)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool GeoIsPointSet(IntPtr gs);
+
+ [LibraryImport(DllPath, EntryPoint = "geo_meos_supported", StringMarshalling = StringMarshalling.Utf8)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool GeoMeosSupported(IntPtr gs);
+
+ [LibraryImport(DllPath, EntryPoint = "geo_points_covered", StringMarshalling = StringMarshalling.Utf8)]
+ internal static partial IntPtr GeoPointsCovered(IntPtr pts, IntPtr gs, [MarshalAs(UnmanagedType.U1)] bool covered);
+
+ [LibraryImport(DllPath, EntryPoint = "geo_clip_linear_geom", StringMarshalling = StringMarshalling.Utf8)]
+ internal static partial IntPtr GeoClipLinearGeom(IntPtr line, IntPtr gs, [MarshalAs(UnmanagedType.U1)] bool inside);
+
[LibraryImport(DllPath, EntryPoint = "geo_edge_ctx_free", StringMarshalling = StringMarshalling.Utf8)]
internal static partial void GeoEdgeCtxFree(IntPtr ctx);
diff --git a/MEOS.NET/Functions/Meos.meos_internal_geo.g.cs b/MEOS.NET/Functions/Meos.meos_internal_geo.g.cs
index 04d0ff3..e204ad7 100644
--- a/MEOS.NET/Functions/Meos.meos_internal_geo.g.cs
+++ b/MEOS.NET/Functions/Meos.meos_internal_geo.g.cs
@@ -252,6 +252,21 @@ public static IntPtr TgeoseqsetRestrictStbox(IntPtr ss, IntPtr box, bool border_
public static IntPtr GeoEdgeCtxMake(IntPtr gs)
=> SafeExecution(() => Native.GeoEdgeCtxMake(gs));
+ public static bool GeoIsPlanarLinear(IntPtr gs)
+ => SafeExecution(() => Native.GeoIsPlanarLinear(gs));
+
+ public static bool GeoIsPointSet(IntPtr gs)
+ => SafeExecution(() => Native.GeoIsPointSet(gs));
+
+ public static bool GeoMeosSupported(IntPtr gs)
+ => SafeExecution(() => Native.GeoMeosSupported(gs));
+
+ public static IntPtr GeoPointsCovered(IntPtr pts, IntPtr gs, bool covered)
+ => SafeExecution(() => Native.GeoPointsCovered(pts, gs, covered));
+
+ public static IntPtr GeoClipLinearGeom(IntPtr line, IntPtr gs, bool inside)
+ => SafeExecution(() => Native.GeoClipLinearGeom(line, gs, inside));
+
public static void GeoEdgeCtxFree(IntPtr ctx)
=> SafeExecution(() => Native.GeoEdgeCtxFree(ctx));
diff --git a/MEOS.NET/Types/Geo.g.cs b/MEOS.NET/Types/Geo.g.cs
index 0a1b42e..6993294 100644
--- a/MEOS.NET/Types/Geo.g.cs
+++ b/MEOS.NET/Types/Geo.g.cs
@@ -96,6 +96,9 @@ public ulong ToH3indexCell(int resolution)
public ulong ToQuadbinCell(int resolution)
=> Meos.GeoToQuadbinCell(this.Ptr, resolution);
+ public ulong ToS2cellCell(int level)
+ => Meos.GeoToS2cellCell(this.Ptr, level);
+
public Set? ToSet()
=> MEOSFactory.WrapSet(Meos.GeoToSet(this.Ptr));
diff --git a/MEOS.NET/Types/Jsonb.g.cs b/MEOS.NET/Types/Jsonb.g.cs
index 3f390e7..b38b1a1 100644
--- a/MEOS.NET/Types/Jsonb.g.cs
+++ b/MEOS.NET/Types/Jsonb.g.cs
@@ -233,6 +233,12 @@ public bool ToBool()
public string ToCstring()
=> Meos.JsonbToCstring(this.Ptr);
+ public float ToFloat4()
+ => Meos.JsonbToFloat4(this.Ptr);
+
+ public double ToFloat8()
+ => Meos.JsonbToFloat8(this.Ptr);
+
public short ToInt16()
=> Meos.JsonbToInt16(this.Ptr);
diff --git a/MEOS.NET/Types/Raquet.g.cs b/MEOS.NET/Types/Raquet.g.cs
index eb367d6..f159d41 100644
--- a/MEOS.NET/Types/Raquet.g.cs
+++ b/MEOS.NET/Types/Raquet.g.cs
@@ -143,6 +143,25 @@ public int Width()
public static Raquet? In(string str)
=> MEOSFactory.WrapRaquet(Meos.RaquetIn(str));
+ public static Raquet? Make(ulong quadbin, int width, int height, MeosPixType pixtype, double nodata, bool has_nodata, byte[] pixels)
+ {
+ GCHandle _pixels = GCHandle.Alloc(pixels, GCHandleType.Pinned);
+ try
+ {
+ return MEOSFactory.WrapRaquet(Meos.RaquetMake(quadbin, width, height, (int) pixtype, nodata, has_nodata, _pixels.AddrOfPinnedObject(), (ulong) pixels.Length));
+ }
+ finally
+ {
+ _pixels.Free();
+ }
+ }
+
+ public static MeosPixType PixtypeFromString(string str)
+ => (MeosPixType) Meos.RaquetPixtypeFromString(str);
+
+ public static ulong PixtypeSize(MeosPixType pixtype)
+ => Meos.RaquetPixtypeSize((int) pixtype);
+
public static Raquet? Read(string path, ulong quadbin)
=> MEOSFactory.WrapRaquet(Meos.RaquetRead(path, quadbin));
diff --git a/MEOS.NET/Types/TGeo.g.cs b/MEOS.NET/Types/TGeo.g.cs
index 3de465c..ad0bcda 100644
--- a/MEOS.NET/Types/TGeo.g.cs
+++ b/MEOS.NET/Types/TGeo.g.cs
@@ -61,6 +61,9 @@ internal TGeo(IntPtr ptr) : base(ptr) { }
public STBox?[] SpaceBoxes(double xsize, double ysize, double zsize, Geo sorigin, bool bitmatrix, bool border_inc)
=> MEOSFactory.WrapSTBoxArray(Meos.TgeoSpaceBoxes(this.Ptr, xsize, ysize, zsize, sorigin.Ptr, bitmatrix, border_inc));
+ public SpaceSplit SpaceSplit(double xsize, double ysize, double zsize, Geo sorigin, bool bitmatrix, bool border_inc)
+ => Meos.TgeoSpaceSplit(this.Ptr, xsize, ysize, zsize, sorigin.Ptr, bitmatrix, border_inc);
+
public STBox?[] SpaceTimeBoxes(double xsize, double ysize, double zsize, Interval duration, Geo sorigin, DateTime torigin, bool bitmatrix, bool border_inc)
{
IntPtr _duration = Marshal.AllocHGlobal(Marshal.SizeOf());
@@ -75,6 +78,20 @@ internal TGeo(IntPtr ptr) : base(ptr) { }
}
}
+ public SpaceTimeSplit SpaceTimeSplit(double xsize, double ysize, double zsize, Interval duration, Geo sorigin, DateTime torigin, bool bitmatrix, bool border_inc)
+ {
+ IntPtr _duration = Marshal.AllocHGlobal(Marshal.SizeOf());
+ try
+ {
+ Marshal.StructureToPtr(duration, _duration, false);
+ return Meos.TgeoSpaceTimeSplit(this.Ptr, xsize, ysize, zsize, _duration, sorigin.Ptr, MEOSConvert.ToTimestampTz(torigin), bitmatrix, border_inc);
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(_duration);
+ }
+ }
+
public STBox?[] SplitEachNStboxes(int elem_count)
=> MEOSFactory.WrapSTBoxArray(Meos.TgeoSplitEachNStboxes(this.Ptr, elem_count));
diff --git a/MEOS.NET/Types/TJsonb.g.cs b/MEOS.NET/Types/TJsonb.g.cs
index 9d58489..9534c9a 100644
--- a/MEOS.NET/Types/TJsonb.g.cs
+++ b/MEOS.NET/Types/TJsonb.g.cs
@@ -18,6 +18,9 @@ internal TJsonb(IntPtr ptr) : base(ptr) { }
public override string ToString()
=> this.Out();
+ public Temporal? ArrayElement(int idx, bool astext, NullHandleType null_handle)
+ => MEOSFactory.WrapTemporal(Meos.TjsonbArrayElement(this.Ptr, idx, astext, (int) null_handle));
+
public Temporal? ArrayLength()
=> MEOSFactory.WrapTemporal(Meos.TjsonbArrayLength(this.Ptr));
@@ -131,6 +134,25 @@ public override string ToString()
}
}
+ public Temporal? ExtractPath(Text[] path_elems, bool astext, NullHandleType null_handle)
+ {
+ IntPtr[] _path_elemsValues = new IntPtr[path_elems.Length];
+ for (int i = 0; i < path_elems.Length; i++)
+ {
+ _path_elemsValues[i] = path_elems[i].Ptr;
+ }
+
+ GCHandle _path_elems = GCHandle.Alloc(_path_elemsValues, GCHandleType.Pinned);
+ try
+ {
+ return MEOSFactory.WrapTemporal(Meos.TjsonbExtractPath(this.Ptr, _path_elems.AddrOfPinnedObject(), path_elems.Length, astext, (int) null_handle));
+ }
+ finally
+ {
+ _path_elems.Free();
+ }
+ }
+
public Temporal? Insert(Text[] keys, Jsonb newjb, bool after)
{
IntPtr[] _keysValues = new IntPtr[keys.Length];
@@ -153,6 +175,9 @@ public override string ToString()
public Temporal? MinusValue(Jsonb jsb)
=> MEOSFactory.WrapTemporal(Meos.TjsonbMinusValue(this.Ptr, jsb.Ptr));
+ public Temporal? ObjectField(Text key, bool astext, NullHandleType null_handle)
+ => MEOSFactory.WrapTemporal(Meos.TjsonbObjectField(this.Ptr, key.Ptr, astext, (int) null_handle));
+
public string Out()
=> Meos.TjsonbOut(this.Ptr);
@@ -184,9 +209,21 @@ public string Out()
public Temporal? StripNulls(bool strip_in_arrays)
=> MEOSFactory.WrapTemporal(Meos.TjsonbStripNulls(this.Ptr, strip_in_arrays));
+ public Temporal? ToTbool(string key, NullHandleType null_handle)
+ => MEOSFactory.WrapTemporal(Meos.TjsonbToTbool(this.Ptr, key, (int) null_handle));
+
+ public Temporal? ToTfloat(string key, InterpType interp, NullHandleType null_handle)
+ => MEOSFactory.WrapTemporal(Meos.TjsonbToTfloat(this.Ptr, key, (int) interp, (int) null_handle));
+
+ public Temporal? ToTint(string key, NullHandleType null_handle)
+ => MEOSFactory.WrapTemporal(Meos.TjsonbToTint(this.Ptr, key, (int) null_handle));
+
public Temporal? ToTtext()
=> MEOSFactory.WrapTemporal(Meos.TjsonbToTtext(this.Ptr));
+ public Temporal? ToTtextKey(string key, NullHandleType null_handle)
+ => MEOSFactory.WrapTemporal(Meos.TjsonbToTtextKey(this.Ptr, key, (int) null_handle));
+
public Jsonb? ValueAtTimestamptz(DateTime t, bool strict)
{
IntPtr _value = Marshal.AllocHGlobal(8);
diff --git a/MEOS.NET/Types/TPoint.g.cs b/MEOS.NET/Types/TPoint.g.cs
index f17ed83..0bbf72a 100644
--- a/MEOS.NET/Types/TPoint.g.cs
+++ b/MEOS.NET/Types/TPoint.g.cs
@@ -17,6 +17,9 @@ internal TPoint(IntPtr ptr) : base(ptr) { }
public Temporal? AngularDifference()
=> MEOSFactory.WrapTemporal(Meos.TpointAngularDifference(this.Ptr));
+ public MvtGeom AsMvtgeom(STBox bounds, int extent, int buffer, bool clip_geom)
+ => Meos.TpointAsMvtgeom(this.Ptr, bounds.Ptr, extent, buffer, clip_geom);
+
public Temporal? AtElevation(Span s)
=> MEOSFactory.WrapTemporal(Meos.TpointAtElevation(this.Ptr, s.Ptr));
diff --git a/MEOS.NET/Types/Text.g.cs b/MEOS.NET/Types/Text.g.cs
index fca12d3..4148362 100644
--- a/MEOS.NET/Types/Text.g.cs
+++ b/MEOS.NET/Types/Text.g.cs
@@ -18,6 +18,12 @@ internal Text(IntPtr ptr) : base(ptr) { }
public override string ToString()
=> this.Out();
+ public uint Hash(uint collid)
+ => Meos.TextHash(this.Ptr, collid);
+
+ public ulong HashExtended(ulong seed, uint collid)
+ => Meos.TextHashExtended(this.Ptr, seed, collid);
+
public Text? Initcap()
=> MEOSFactory.WrapText(Meos.TextInitcap(this.Ptr));
diff --git a/tools/objectgen.py b/tools/objectgen.py
index f5c48f3..6f9cae7 100644
--- a/tools/objectgen.py
+++ b/tools/objectgen.py
@@ -74,14 +74,18 @@
"DateADT *": ("DateOnly", 4, "MEOSConvert.ToDateOnly(Marshal.ReadInt32({0}))"),
}
-# C types the object layer passes and returns as C# scalars, keyed by the cleaned
-# C spelling. Everything else is either a wrapped class pointer or deferred.
-PASSTHROUGH_C = {
- "bool", "char", "int", "int8", "int8_t", "uint8", "uint8_t", "int16", "int16_t",
- "uint16", "uint16_t", "int32", "int32_t", "uint32", "uint32_t", "int64",
- "int64_t", "uint64", "uint64_t", "long", "double", "float", "size_t",
- "char *", "void",
-}
+def is_scalar(cs_type: str) -> bool:
+ """Whether the wrapper already states this as a C# value the layer hands on.
+
+ The wrapper's own C# type is what decides it: codegen resolves every scalar
+ the catalog names — through the typedefs it carries, so `S2CellId` reads
+ `ulong` and `float8` reads `double` — and a struct it carries by value is a
+ value too. A second list of C spellings here would answer for the ones the
+ layer was told about and defer the rest."""
+ return cs_type in _SCALAR_CS or cs_type in codegen.BY_VALUE_STRUCTS
+
+
+_SCALAR_CS = set(codegen.SCALAR_MAP.values()) | {"void", "bool", "string", "string?"}
# Acronym runs the error names carry, kept upper-case so the C# spelling reads
# the way the catalog's own camelCase names do (`asMFJSON`).
@@ -308,7 +312,9 @@ def map_return(self, f: dict, wrapper_ret: str) -> tuple[str, str] | None:
return ("DateOnly", "MEOSConvert.ToDateOnly($)")
if wrapper_ret in ("string", "string?"):
return (wrapper_ret, "$")
- if c in PASSTHROUGH_C and wrapper_ret != "IntPtr":
+ if c in codegen.ENUM_TYPES:
+ return (enum_type_name(c), f"({enum_type_name(c)}) $")
+ if is_scalar(wrapper_ret):
return (wrapper_ret, "$")
cls = self.m.class_for_ctype(c)
if cls and wrapper_ret == "IntPtr":
@@ -361,9 +367,13 @@ def map_param(self, c_type: str, cs_type: str, name: str) -> tuple[str, str] | N
return ("DateTime", f"MEOSConvert.ToTimestampTz({name})")
if c == "DateADT":
return ("DateOnly", f"MEOSConvert.ToDateADT({name})")
- if c == "interpType":
- return ("InterpType", f"(int) {name}")
- if c in PASSTHROUGH_C and cs_type != "IntPtr":
+ if c in codegen.ENUM_TYPES:
+ # The wrapper takes the enum's value as an int, and the catalog
+ # already names every enum the surface uses — so a method takes the
+ # C# enum whichever one it is, rather than the one enum the layer
+ # was told about.
+ return (enum_type_name(c), f"(int) {name}")
+ if is_scalar(cs_type):
return (cs_type, name)
if cs_type == "string":
return ("string", name)