diff --git a/ExampleApp/Program.cs b/ExampleApp/Program.cs index 119daaf..fd9f339 100644 --- a/ExampleApp/Program.cs +++ b/ExampleApp/Program.cs @@ -10,14 +10,14 @@ Console.WriteLine("Reading a temporal float instant from \"25.0@2024-12-06\""); Temporal tfi = TFloat.In("25.0@2024-12-06")!; Console.WriteLine($" class : {tfi.GetType().Name}"); - Console.WriteLine($" text : {Meos.TfloatOut(tfi.Ptr, 15)}"); + Console.WriteLine($" text : {tfi}"); Console.WriteLine($" start timestamp : {tfi.StartTimestamptz():u}"); Console.WriteLine($" MF-JSON : {tfi.AsMFJSON(false, 0, 6, string.Empty)}"); Console.WriteLine($" always 25.0? : {Meos.AlwaysEqTfloatFloat(tfi.Ptr, 25.0) == 1}\n"); Console.WriteLine("Making one from a value and a moment"); Temporal made = TFloatInst.Make(26.0, DateTime.UtcNow)!; - Console.WriteLine($" text : {Meos.TfloatOut(made.Ptr, 15)}"); + Console.WriteLine($" text : {made}"); Console.WriteLine(" adding 34 to its value"); Temporal sum = MEOSFactory.WrapTemporal(Meos.AddTfloatFloat(made.Ptr, 34.0))!; Console.WriteLine($" text : {Meos.TfloatOut(sum.Ptr, 15)}"); @@ -29,7 +29,7 @@ Console.WriteLine($" spans : {spanset.NumSpans()}"); foreach (Span? span in spanset.Spanarr()) { - Console.WriteLine($" {((FloatSpan)span!).Out(15)}"); + Console.WriteLine($" {span}"); } Console.WriteLine($" contains 9.0? : {Meos.ContainsSpansetFloat(spanset.Ptr, 9.0)}"); diff --git a/MEOS.NET.Tests/TextOutputTests.cs b/MEOS.NET.Tests/TextOutputTests.cs new file mode 100644 index 0000000..10820b1 --- /dev/null +++ b/MEOS.NET.Tests/TextOutputTests.cs @@ -0,0 +1,50 @@ +using MEOS.NET.Types; + +namespace MEOS.NET.Tests +{ + /// + /// A value prints as the text MEOS writes it as. MEOS publishes that text per + /// concrete type, so a class carries ToString exactly where MEOS + /// publishes an output for its own type. + /// + [TestClass] + public class TextOutputTests : MeosTest + { + [TestMethod] + public void ATemporalFloatPrintsAsMeosWritesIt() + { + Temporal temp = TFloat.In("[25.5@2024-12-06, 27.5@2024-12-07]")!; + + Assert.AreEqual( + "[25.5@2024-12-06 00:00:00+00, 27.5@2024-12-07 00:00:00+00]", + temp.ToString()); + } + + [TestMethod] + public void ASpanPrintsAsMeosWritesIt() + { + SpanSet spanset = FloatSpanSet.In("{[8, 10], [11, 12]}")!; + + Assert.AreEqual("[8, 10]", spanset.StartSpan()!.ToString()); + Assert.AreEqual("{[8, 10], [11, 12]}", spanset.ToString()); + } + + [TestMethod] + public void ABoxPrintsAsMeosWritesIt() + { + STBox box = STBox.In("STBOX X((1,1),(2,2))")!; + + Assert.AreEqual("STBOX X((1,1),(2,2))", box.ToString()); + } + + [TestMethod] + public void TheTextComesFromTheClassOfTheValue() + { + // Wrapping answers the concrete class, so the text is that class's. + Temporal instant = TFloat.In("25.5@2024-12-06")!; + + Assert.IsInstanceOfType(instant, typeof(TFloatInst)); + Assert.AreEqual("25.5@2024-12-06 00:00:00+00", instant.ToString()); + } + } +} diff --git a/MEOS.NET/Types/BigIntSet.g.cs b/MEOS.NET/Types/BigIntSet.g.cs index 8c856d2..c2cbf30 100644 --- a/MEOS.NET/Types/BigIntSet.g.cs +++ b/MEOS.NET/Types/BigIntSet.g.cs @@ -11,6 +11,10 @@ public class BigIntSet : Set { internal BigIntSet(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(); + public long EndValue() => Meos.BigintsetEndValue(this.Ptr); diff --git a/MEOS.NET/Types/BigIntSpan.g.cs b/MEOS.NET/Types/BigIntSpan.g.cs index 008919a..7360c3d 100644 --- a/MEOS.NET/Types/BigIntSpan.g.cs +++ b/MEOS.NET/Types/BigIntSpan.g.cs @@ -11,6 +11,10 @@ public class BigIntSpan : Span { internal BigIntSpan(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(); + public Span? Expand(long value) => MEOSFactory.WrapSpan(Meos.BigintspanExpand(this.Ptr, value)); diff --git a/MEOS.NET/Types/BigIntSpanSet.g.cs b/MEOS.NET/Types/BigIntSpanSet.g.cs index 314653a..e99a8fa 100644 --- a/MEOS.NET/Types/BigIntSpanSet.g.cs +++ b/MEOS.NET/Types/BigIntSpanSet.g.cs @@ -11,6 +11,10 @@ public class BigIntSpanSet : SpanSet { internal BigIntSpanSet(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(); + public long Lower() => Meos.BigintspansetLower(this.Ptr); diff --git a/MEOS.NET/Types/CbufferSet.g.cs b/MEOS.NET/Types/CbufferSet.g.cs index 4ab70b1..52cf06f 100644 --- a/MEOS.NET/Types/CbufferSet.g.cs +++ b/MEOS.NET/Types/CbufferSet.g.cs @@ -11,6 +11,10 @@ public class CbufferSet : Set { internal CbufferSet(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(15); + public string Out(int maxdd) => Meos.CbuffersetOut(this.Ptr, maxdd); diff --git a/MEOS.NET/Types/DateSet.g.cs b/MEOS.NET/Types/DateSet.g.cs index af3f604..81b5c43 100644 --- a/MEOS.NET/Types/DateSet.g.cs +++ b/MEOS.NET/Types/DateSet.g.cs @@ -11,6 +11,10 @@ public class DateSet : Set { internal DateSet(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(); + public DateOnly EndValue() => MEOSConvert.ToDateOnly(Meos.DatesetEndValue(this.Ptr)); diff --git a/MEOS.NET/Types/DateSpan.g.cs b/MEOS.NET/Types/DateSpan.g.cs index 11fab6c..cc95052 100644 --- a/MEOS.NET/Types/DateSpan.g.cs +++ b/MEOS.NET/Types/DateSpan.g.cs @@ -11,6 +11,10 @@ public class DateSpan : Span { internal DateSpan(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(); + public DateOnly Lower() => MEOSConvert.ToDateOnly(Meos.DatespanLower(this.Ptr)); diff --git a/MEOS.NET/Types/DateSpanSet.g.cs b/MEOS.NET/Types/DateSpanSet.g.cs index c925128..7b671a2 100644 --- a/MEOS.NET/Types/DateSpanSet.g.cs +++ b/MEOS.NET/Types/DateSpanSet.g.cs @@ -11,6 +11,10 @@ public class DateSpanSet : SpanSet { internal DateSpanSet(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(); + public Set? Dates() => MEOSFactory.WrapSet(Meos.DatespansetDates(this.Ptr)); diff --git a/MEOS.NET/Types/FloatSet.g.cs b/MEOS.NET/Types/FloatSet.g.cs index 6249570..be1b2fa 100644 --- a/MEOS.NET/Types/FloatSet.g.cs +++ b/MEOS.NET/Types/FloatSet.g.cs @@ -11,6 +11,10 @@ public class FloatSet : Set { internal FloatSet(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(15); + public Set? Ceil() => MEOSFactory.WrapSet(Meos.FloatsetCeil(this.Ptr)); diff --git a/MEOS.NET/Types/FloatSpan.g.cs b/MEOS.NET/Types/FloatSpan.g.cs index ca88751..44eac3f 100644 --- a/MEOS.NET/Types/FloatSpan.g.cs +++ b/MEOS.NET/Types/FloatSpan.g.cs @@ -11,6 +11,10 @@ public class FloatSpan : Span { internal FloatSpan(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(15); + public Span? Ceil() => MEOSFactory.WrapSpan(Meos.FloatspanCeil(this.Ptr)); diff --git a/MEOS.NET/Types/FloatSpanSet.g.cs b/MEOS.NET/Types/FloatSpanSet.g.cs index 83f29b5..2e7ed4a 100644 --- a/MEOS.NET/Types/FloatSpanSet.g.cs +++ b/MEOS.NET/Types/FloatSpanSet.g.cs @@ -11,6 +11,10 @@ public class FloatSpanSet : SpanSet { internal FloatSpanSet(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(15); + public SpanSet? Ceil() => MEOSFactory.WrapSpanSet(Meos.FloatspansetCeil(this.Ptr)); diff --git a/MEOS.NET/Types/IntSet.g.cs b/MEOS.NET/Types/IntSet.g.cs index cd912d1..296ffd7 100644 --- a/MEOS.NET/Types/IntSet.g.cs +++ b/MEOS.NET/Types/IntSet.g.cs @@ -11,6 +11,10 @@ public class IntSet : Set { internal IntSet(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(); + public int EndValue() => Meos.IntsetEndValue(this.Ptr); diff --git a/MEOS.NET/Types/IntSpan.g.cs b/MEOS.NET/Types/IntSpan.g.cs index 1bcda31..ae68f62 100644 --- a/MEOS.NET/Types/IntSpan.g.cs +++ b/MEOS.NET/Types/IntSpan.g.cs @@ -11,6 +11,10 @@ public class IntSpan : Span { internal IntSpan(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(); + public Span? Expand(int value) => MEOSFactory.WrapSpan(Meos.IntspanExpand(this.Ptr, value)); diff --git a/MEOS.NET/Types/IntSpanSet.g.cs b/MEOS.NET/Types/IntSpanSet.g.cs index 5e48d6b..4772fbc 100644 --- a/MEOS.NET/Types/IntSpanSet.g.cs +++ b/MEOS.NET/Types/IntSpanSet.g.cs @@ -11,6 +11,10 @@ public class IntSpanSet : SpanSet { internal IntSpanSet(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(); + public int Lower() => Meos.IntspansetLower(this.Ptr); diff --git a/MEOS.NET/Types/NpointSet.g.cs b/MEOS.NET/Types/NpointSet.g.cs index 6edafb3..cc40491 100644 --- a/MEOS.NET/Types/NpointSet.g.cs +++ b/MEOS.NET/Types/NpointSet.g.cs @@ -11,6 +11,10 @@ public class NpointSet : Set { internal NpointSet(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(15); + public string Out(int maxdd) => Meos.NpointsetOut(this.Ptr, maxdd); diff --git a/MEOS.NET/Types/PoseSet.g.cs b/MEOS.NET/Types/PoseSet.g.cs index 0cbd1d3..c11b9fc 100644 --- a/MEOS.NET/Types/PoseSet.g.cs +++ b/MEOS.NET/Types/PoseSet.g.cs @@ -11,6 +11,10 @@ public class PoseSet : Set { internal PoseSet(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(15); + public string Out(int maxdd) => Meos.PosesetOut(this.Ptr, maxdd); diff --git a/MEOS.NET/Types/STBox.g.cs b/MEOS.NET/Types/STBox.g.cs index d18080a..9848e21 100644 --- a/MEOS.NET/Types/STBox.g.cs +++ b/MEOS.NET/Types/STBox.g.cs @@ -11,6 +11,10 @@ public class STBox : Box { internal STBox(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(15); + public double Area(bool spheroid) => Meos.StboxArea(this.Ptr, spheroid); diff --git a/MEOS.NET/Types/TBigint.g.cs b/MEOS.NET/Types/TBigint.g.cs index 6137372..a042297 100644 --- a/MEOS.NET/Types/TBigint.g.cs +++ b/MEOS.NET/Types/TBigint.g.cs @@ -11,6 +11,10 @@ public class TBigint : TNumber { internal TBigint(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(); + public long EndValue() => Meos.TbigintEndValue(this.Ptr); diff --git a/MEOS.NET/Types/TBool.g.cs b/MEOS.NET/Types/TBool.g.cs index 06304be..64d2b27 100644 --- a/MEOS.NET/Types/TBool.g.cs +++ b/MEOS.NET/Types/TBool.g.cs @@ -11,6 +11,10 @@ public class TBool : TAlpha { internal TBool(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(); + public Temporal? AtValue(bool b) => MEOSFactory.WrapTemporal(Meos.TboolAtValue(this.Ptr, b)); diff --git a/MEOS.NET/Types/TBox.g.cs b/MEOS.NET/Types/TBox.g.cs index 9058f99..d7e3c17 100644 --- a/MEOS.NET/Types/TBox.g.cs +++ b/MEOS.NET/Types/TBox.g.cs @@ -11,6 +11,10 @@ public class TBox : Box { internal TBox(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(15); + public int Cmp(TBox box2) => Meos.TboxCmp(this.Ptr, box2.Ptr); diff --git a/MEOS.NET/Types/TFloat.g.cs b/MEOS.NET/Types/TFloat.g.cs index 8459555..f1a4452 100644 --- a/MEOS.NET/Types/TFloat.g.cs +++ b/MEOS.NET/Types/TFloat.g.cs @@ -11,6 +11,10 @@ public class TFloat : TNumber { internal TFloat(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(15); + public Temporal? AtValue(double d) => MEOSFactory.WrapTemporal(Meos.TfloatAtValue(this.Ptr, d)); diff --git a/MEOS.NET/Types/TInt.g.cs b/MEOS.NET/Types/TInt.g.cs index 028c1bf..368f8d5 100644 --- a/MEOS.NET/Types/TInt.g.cs +++ b/MEOS.NET/Types/TInt.g.cs @@ -11,6 +11,10 @@ public class TInt : TNumber { internal TInt(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(); + public Temporal? AtValue(int i) => MEOSFactory.WrapTemporal(Meos.TintAtValue(this.Ptr, i)); diff --git a/MEOS.NET/Types/TJsonb.g.cs b/MEOS.NET/Types/TJsonb.g.cs index f8797a5..d5cde93 100644 --- a/MEOS.NET/Types/TJsonb.g.cs +++ b/MEOS.NET/Types/TJsonb.g.cs @@ -11,6 +11,10 @@ public class TJsonb : TAlpha { internal TJsonb(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(); + public Temporal? ArrayLength() => MEOSFactory.WrapTemporal(Meos.TjsonbArrayLength(this.Ptr)); diff --git a/MEOS.NET/Types/TNpoint.g.cs b/MEOS.NET/Types/TNpoint.g.cs index 316dfed..5581560 100644 --- a/MEOS.NET/Types/TNpoint.g.cs +++ b/MEOS.NET/Types/TNpoint.g.cs @@ -11,6 +11,10 @@ public class TNpoint : TSpatial { internal TNpoint(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(15); + public Temporal? AtNpointset(Set s) => MEOSFactory.WrapTemporal(Meos.TnpointAtNpointset(this.Ptr, s.Ptr)); diff --git a/MEOS.NET/Types/TRGeometry.g.cs b/MEOS.NET/Types/TRGeometry.g.cs index f2875ce..1a67206 100644 --- a/MEOS.NET/Types/TRGeometry.g.cs +++ b/MEOS.NET/Types/TRGeometry.g.cs @@ -11,6 +11,10 @@ public class TRGeometry : TSpatial { internal TRGeometry(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(); + public new Temporal? AfterTimestamptz(DateTime t, bool strict) => MEOSFactory.WrapTemporal(Meos.TrgeometryAfterTimestamptz(this.Ptr, MEOSConvert.ToTimestampTz(t), strict)); diff --git a/MEOS.NET/Types/TSpatial.g.cs b/MEOS.NET/Types/TSpatial.g.cs index 1c87dd9..5a543c1 100644 --- a/MEOS.NET/Types/TSpatial.g.cs +++ b/MEOS.NET/Types/TSpatial.g.cs @@ -11,6 +11,10 @@ public class TSpatial : Temporal { internal TSpatial(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(15); + public string AsEWKT(int maxdd) => Meos.TspatialAsEwkt(this.Ptr, maxdd); diff --git a/MEOS.NET/Types/TText.g.cs b/MEOS.NET/Types/TText.g.cs index 729da6d..e7cffb2 100644 --- a/MEOS.NET/Types/TText.g.cs +++ b/MEOS.NET/Types/TText.g.cs @@ -11,6 +11,10 @@ public class TText : TAlpha { internal TText(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(); + public Temporal? Initcap() => MEOSFactory.WrapTemporal(Meos.TtextInitcap(this.Ptr)); diff --git a/MEOS.NET/Types/TextSet.g.cs b/MEOS.NET/Types/TextSet.g.cs index 4bbfb5a..5343968 100644 --- a/MEOS.NET/Types/TextSet.g.cs +++ b/MEOS.NET/Types/TextSet.g.cs @@ -11,6 +11,10 @@ public class TextSet : Set { internal TextSet(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(); + public Set? Initcap() => MEOSFactory.WrapSet(Meos.TextsetInitcap(this.Ptr)); diff --git a/MEOS.NET/Types/TsTzSet.g.cs b/MEOS.NET/Types/TsTzSet.g.cs index 937f2ec..e884934 100644 --- a/MEOS.NET/Types/TsTzSet.g.cs +++ b/MEOS.NET/Types/TsTzSet.g.cs @@ -11,6 +11,10 @@ public class TsTzSet : Set { internal TsTzSet(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(); + public DateTime EndValue() => MEOSConvert.ToDateTime(Meos.TstzsetEndValue(this.Ptr)); diff --git a/MEOS.NET/Types/TsTzSpan.g.cs b/MEOS.NET/Types/TsTzSpan.g.cs index 00b26c7..81d675a 100644 --- a/MEOS.NET/Types/TsTzSpan.g.cs +++ b/MEOS.NET/Types/TsTzSpan.g.cs @@ -11,6 +11,10 @@ public class TsTzSpan : Span { internal TsTzSpan(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(); + public DateTime Lower() => MEOSConvert.ToDateTime(Meos.TstzspanLower(this.Ptr)); diff --git a/MEOS.NET/Types/TsTzSpanSet.g.cs b/MEOS.NET/Types/TsTzSpanSet.g.cs index d27013b..aa690a6 100644 --- a/MEOS.NET/Types/TsTzSpanSet.g.cs +++ b/MEOS.NET/Types/TsTzSpanSet.g.cs @@ -11,6 +11,10 @@ public class TsTzSpanSet : SpanSet { internal TsTzSpanSet(IntPtr ptr) : base(ptr) { } + /// The text MEOS writes this value as. + public override string ToString() + => this.Out(); + public DateTime EndTimestamptz() => MEOSConvert.ToDateTime(Meos.TstzspansetEndTimestamptz(this.Ptr)); diff --git a/tools/objectgen.py b/tools/objectgen.py index 8ca0212..2a0e4b8 100644 --- a/tools/objectgen.py +++ b/tools/objectgen.py @@ -401,6 +401,7 @@ def emit_class(self, cls: str) -> str: f" internal {cls}(IntPtr ptr) : base(ptr) {{ }}", "", ] + lines += self.to_string(cls, methods) for m in methods: args = ", ".join(f"{t} {ident(n)}" for t, n in m.params) new = "new " if (m.name, tuple(t for t, _ in m.params)) in inherited else "" @@ -411,6 +412,32 @@ def emit_class(self, cls: str) -> str: lines += [" }", "}", ""] return "\n".join(lines) + def to_string(self, cls: str, methods: list) -> list[str]: + """`ToString` over the class's own text output, where MEOS publishes one. + + MEOS publishes text output per concrete type — `tfloat_out`, `stbox_out`, + `floatspan_out` — and keeps the generic dispatchers internal, so a class + that carries an `Out` of its own is exactly a class whose values MEOS + writes. The decimal digits are the default the catalog records for that + C type's text encoding.""" + out = next((m for m in methods if m.name == "Out" and not m.static + and [t for t, _ in m.params] in ([], ["int"])), None) + if out is None: + return [] + ctype = self.m.ctype.get(cls) + encoding = self.m.idl.get("typeEncodings", {}).get(ctype, {}) + aux = {a["name"]: a["default"] for a in encoding.get("out_aux", [])} + argument = str(aux.get("maxdd", "")) if out.params else "" + if out.params and not argument: + return [] + nullable = "?" if out.ret.endswith("?") else "" + return [ + " /// The text MEOS writes this value as.", + f" public override string{nullable} ToString()", + f" => this.Out({argument});", + "", + ] + def doc_for(self, cls: str) -> str: node = self.m.om["lattice"].get(cls) if node and node.get("doc"):