Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,4 @@ jobs:
uses: MobilityDB/MEOS-API/.github/actions/check-test-outcome@master
with:
log: test.log
min-tests: "115"
min-tests: "118"
48 changes: 48 additions & 0 deletions example_pointer_boundary_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package gomeos

// The generated package and this one each declare their own cgo view of the
// MEOS structs, so a `*C.Temporal` from one is a DIFFERENT Go type in the other
// and Inner() cannot cross between them. The opaque pointer is what both sides
// agree on, which is what these examples exercise: a handle built here reaches
// a generated wrapper, the pointer survives the crossing unchanged, and an
// absent handle stays absent.

import (
"fmt"
"unsafe"

"github.com/MobilityDB/GoMEOS/functions"
)

func ExampleTemporalFromPointer() {
tb := NewTBoolSeq("{FALSE@2022-10-01, FALSE@2022-10-02, TRUE@2022-10-03}")

// Hand this package's handle to the generated package through the pointer,
// and let a generated wrapper read it.
crossed := functions.TemporalFromPointer(unsafe.Pointer(tb.Inner()))
instants, err := functions.TemporalNumInstants(crossed)
subtype, err2 := functions.TemporalSubtype(crossed)
fmt.Println(instants, err, subtype, err2)
// Output:
// 3 <nil> Sequence <nil>
}

func ExampleTemporal_Pointer() {
tb := NewTBoolSeq("{FALSE@2022-10-01, TRUE@2022-10-03}")
crossed := functions.TemporalFromPointer(unsafe.Pointer(tb.Inner()))

// The pointer survives the round trip unchanged, so the boundary carries
// the handle rather than copying what it points at.
fmt.Println(crossed.Pointer() == unsafe.Pointer(tb.Inner()))
// Output:
// true
}

func ExampleTemporalFromPointer_absent() {
// A MEOS entry answering NULL crosses as a nil handle rather than a
// dereference, and a nil handle answers a nil pointer.
absent := functions.TemporalFromPointer(nil)
fmt.Println(absent == nil, absent.Pointer() == nil)
// Output:
// true true
}
22 changes: 22 additions & 0 deletions functions/meos_meos_pointcloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,28 @@ func PcpatchNpoints(pa *Pcpatch) (_r0 uint32, _err error) {
}


// PcpatchPointN wraps MEOS C function pcpatch_point_n.
func PcpatchPointN(pa *Pcpatch, n int) (_r0 *Pcpoint, _err error) {
C.meos_errno_reset()
_cret := C.pcpatch_point_n(pa._inner, C.int(n))
if _err = meosError(); _err != nil {
return
}
return &Pcpoint{_inner: _cret}, nil
}


// PcpatchPoints wraps MEOS C function pcpatch_points.
func PcpatchPoints(pa *Pcpatch, count unsafe.Pointer) (_r0 unsafe.Pointer, _err error) {
C.meos_errno_reset()
_cret := C.pcpatch_points(pa._inner, (*C.int)(unsafe.Pointer(count)))
if _err = meosError(); _err != nil {
return
}
return unsafe.Pointer(_cret), nil
}


// PcpatchHash wraps MEOS C function pcpatch_hash.
func PcpatchHash(pa *Pcpatch) (_r0 uint32, _err error) {
C.meos_errno_reset()
Expand Down
58 changes: 58 additions & 0 deletions functions/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,62 +26,120 @@ var _ = unsafe.Pointer(nil)
// -------------------- opaque handle types --------------------
type Temporal struct { _inner *C.Temporal }
func (x *Temporal) Inner() *C.Temporal { if x == nil { return nil }; return x._inner }
func (x *Temporal) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func TemporalFromPointer(p unsafe.Pointer) *Temporal { if p == nil { return nil }; return &Temporal{_inner: (*C.Temporal)(p)} }
type TInstant struct { _inner *C.TInstant }
func (x *TInstant) Inner() *C.TInstant { if x == nil { return nil }; return x._inner }
func (x *TInstant) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func TInstantFromPointer(p unsafe.Pointer) *TInstant { if p == nil { return nil }; return &TInstant{_inner: (*C.TInstant)(p)} }
type TSequence struct { _inner *C.TSequence }
func (x *TSequence) Inner() *C.TSequence { if x == nil { return nil }; return x._inner }
func (x *TSequence) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func TSequenceFromPointer(p unsafe.Pointer) *TSequence { if p == nil { return nil }; return &TSequence{_inner: (*C.TSequence)(p)} }
type TSequenceSet struct { _inner *C.TSequenceSet }
func (x *TSequenceSet) Inner() *C.TSequenceSet { if x == nil { return nil }; return x._inner }
func (x *TSequenceSet) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func TSequenceSetFromPointer(p unsafe.Pointer) *TSequenceSet { if p == nil { return nil }; return &TSequenceSet{_inner: (*C.TSequenceSet)(p)} }
type STBox struct { _inner *C.STBox }
func (x *STBox) Inner() *C.STBox { if x == nil { return nil }; return x._inner }
func (x *STBox) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func STBoxFromPointer(p unsafe.Pointer) *STBox { if p == nil { return nil }; return &STBox{_inner: (*C.STBox)(p)} }
type TBox struct { _inner *C.TBox }
func (x *TBox) Inner() *C.TBox { if x == nil { return nil }; return x._inner }
func (x *TBox) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func TBoxFromPointer(p unsafe.Pointer) *TBox { if p == nil { return nil }; return &TBox{_inner: (*C.TBox)(p)} }
type Span struct { _inner *C.Span }
func (x *Span) Inner() *C.Span { if x == nil { return nil }; return x._inner }
func (x *Span) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func SpanFromPointer(p unsafe.Pointer) *Span { if p == nil { return nil }; return &Span{_inner: (*C.Span)(p)} }
type SpanSet struct { _inner *C.SpanSet }
func (x *SpanSet) Inner() *C.SpanSet { if x == nil { return nil }; return x._inner }
func (x *SpanSet) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func SpanSetFromPointer(p unsafe.Pointer) *SpanSet { if p == nil { return nil }; return &SpanSet{_inner: (*C.SpanSet)(p)} }
type Set struct { _inner *C.Set }
func (x *Set) Inner() *C.Set { if x == nil { return nil }; return x._inner }
func (x *Set) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func SetFromPointer(p unsafe.Pointer) *Set { if p == nil { return nil }; return &Set{_inner: (*C.Set)(p)} }
type Geom struct { _inner *C.GSERIALIZED }
func (x *Geom) Inner() *C.GSERIALIZED { if x == nil { return nil }; return x._inner }
func (x *Geom) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func GeomFromPointer(p unsafe.Pointer) *Geom { if p == nil { return nil }; return &Geom{_inner: (*C.GSERIALIZED)(p)} }
type Interval struct { _inner *C.Interval }
func (x *Interval) Inner() *C.Interval { if x == nil { return nil }; return x._inner }
func (x *Interval) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func IntervalFromPointer(p unsafe.Pointer) *Interval { if p == nil { return nil }; return &Interval{_inner: (*C.Interval)(p)} }
type Npoint struct { _inner *C.Npoint }
func (x *Npoint) Inner() *C.Npoint { if x == nil { return nil }; return x._inner }
func (x *Npoint) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func NpointFromPointer(p unsafe.Pointer) *Npoint { if p == nil { return nil }; return &Npoint{_inner: (*C.Npoint)(p)} }
type Nsegment struct { _inner *C.Nsegment }
func (x *Nsegment) Inner() *C.Nsegment { if x == nil { return nil }; return x._inner }
func (x *Nsegment) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func NsegmentFromPointer(p unsafe.Pointer) *Nsegment { if p == nil { return nil }; return &Nsegment{_inner: (*C.Nsegment)(p)} }
type Cbuffer struct { _inner *C.Cbuffer }
func (x *Cbuffer) Inner() *C.Cbuffer { if x == nil { return nil }; return x._inner }
func (x *Cbuffer) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func CbufferFromPointer(p unsafe.Pointer) *Cbuffer { if p == nil { return nil }; return &Cbuffer{_inner: (*C.Cbuffer)(p)} }
type Pose struct { _inner *C.Pose }
func (x *Pose) Inner() *C.Pose { if x == nil { return nil }; return x._inner }
func (x *Pose) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func PoseFromPointer(p unsafe.Pointer) *Pose { if p == nil { return nil }; return &Pose{_inner: (*C.Pose)(p)} }
type Jsonb struct { _inner *C.Jsonb }
func (x *Jsonb) Inner() *C.Jsonb { if x == nil { return nil }; return x._inner }
func (x *Jsonb) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func JsonbFromPointer(p unsafe.Pointer) *Jsonb { if p == nil { return nil }; return &Jsonb{_inner: (*C.Jsonb)(p)} }
type JsonPath struct { _inner *C.JsonPath }
func (x *JsonPath) Inner() *C.JsonPath { if x == nil { return nil }; return x._inner }
func (x *JsonPath) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func JsonPathFromPointer(p unsafe.Pointer) *JsonPath { if p == nil { return nil }; return &JsonPath{_inner: (*C.JsonPath)(p)} }
type Pcpoint struct { _inner *C.Pcpoint }
func (x *Pcpoint) Inner() *C.Pcpoint { if x == nil { return nil }; return x._inner }
func (x *Pcpoint) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func PcpointFromPointer(p unsafe.Pointer) *Pcpoint { if p == nil { return nil }; return &Pcpoint{_inner: (*C.Pcpoint)(p)} }
type Pcpatch struct { _inner *C.Pcpatch }
func (x *Pcpatch) Inner() *C.Pcpatch { if x == nil { return nil }; return x._inner }
func (x *Pcpatch) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func PcpatchFromPointer(p unsafe.Pointer) *Pcpatch { if p == nil { return nil }; return &Pcpatch{_inner: (*C.Pcpatch)(p)} }
type TPCBox struct { _inner *C.TPCBox }
func (x *TPCBox) Inner() *C.TPCBox { if x == nil { return nil }; return x._inner }
func (x *TPCBox) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func TPCBoxFromPointer(p unsafe.Pointer) *TPCBox { if p == nil { return nil }; return &TPCBox{_inner: (*C.TPCBox)(p)} }
type MeosArray struct { _inner *C.MeosArray }
func (x *MeosArray) Inner() *C.MeosArray { if x == nil { return nil }; return x._inner }
func (x *MeosArray) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func MeosArrayFromPointer(p unsafe.Pointer) *MeosArray { if p == nil { return nil }; return &MeosArray{_inner: (*C.MeosArray)(p)} }
type PCSchema struct { _inner *C.PCSCHEMA }
func (x *PCSchema) Inner() *C.PCSCHEMA { if x == nil { return nil }; return x._inner }
func (x *PCSchema) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func PCSchemaFromPointer(p unsafe.Pointer) *PCSchema { if p == nil { return nil }; return &PCSchema{_inner: (*C.PCSCHEMA)(p)} }
type SkipList struct { _inner *C.SkipList }
func (x *SkipList) Inner() *C.SkipList { if x == nil { return nil }; return x._inner }
func (x *SkipList) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func SkipListFromPointer(p unsafe.Pointer) *SkipList { if p == nil { return nil }; return &SkipList{_inner: (*C.SkipList)(p)} }
type RTree struct { _inner *C.RTree }
func (x *RTree) Inner() *C.RTree { if x == nil { return nil }; return x._inner }
func (x *RTree) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func RTreeFromPointer(p unsafe.Pointer) *RTree { if p == nil { return nil }; return &RTree{_inner: (*C.RTree)(p)} }
type Match struct { _inner *C.Match }
func (x *Match) Inner() *C.Match { if x == nil { return nil }; return x._inner }
func (x *Match) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func MatchFromPointer(p unsafe.Pointer) *Match { if p == nil { return nil }; return &Match{_inner: (*C.Match)(p)} }
type Box3D struct { _inner *C.BOX3D }
func (x *Box3D) Inner() *C.BOX3D { if x == nil { return nil }; return x._inner }
func (x *Box3D) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func Box3DFromPointer(p unsafe.Pointer) *Box3D { if p == nil { return nil }; return &Box3D{_inner: (*C.BOX3D)(p)} }
type GBox struct { _inner *C.GBOX }
func (x *GBox) Inner() *C.GBOX { if x == nil { return nil }; return x._inner }
func (x *GBox) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func GBoxFromPointer(p unsafe.Pointer) *GBox { if p == nil { return nil }; return &GBox{_inner: (*C.GBOX)(p)} }
type AFFINE struct { _inner *C.AFFINE }
func (x *AFFINE) Inner() *C.AFFINE { if x == nil { return nil }; return x._inner }
func (x *AFFINE) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func AFFINEFromPointer(p unsafe.Pointer) *AFFINE { if p == nil { return nil }; return &AFFINE{_inner: (*C.AFFINE)(p)} }
type PJContext struct { _inner *C.PJ_CONTEXT }
func (x *PJContext) Inner() *C.PJ_CONTEXT { if x == nil { return nil }; return x._inner }
func (x *PJContext) Pointer() unsafe.Pointer { if x == nil { return nil }; return unsafe.Pointer(x._inner) }
func PJContextFromPointer(p unsafe.Pointer) *PJContext { if p == nil { return nil }; return &PJContext{_inner: (*C.PJ_CONTEXT)(p)} }

// -------------------- enums --------------------
type TempSubtype C.tempSubtype
Expand Down
16 changes: 16 additions & 0 deletions tools/codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,22 @@ def referenced(go_name: str) -> bool:
f"func (x *{go_name}) Inner() *C.{c_name} {{ "
f"if x == nil {{ return nil }}; return x._inner }}"
)
# A cgo type belongs to the package that declares it, so this package's
# `*C.{c_name}` and a caller's own `*C.{c_name}` are DIFFERENT Go types
# and Inner() cannot cross a package boundary. The handle is an opaque
# MEOS pointer either way, so the pointer itself is the boundary -- the
# same contract MEOS.NET's generated handles carry as IntPtr. A nil
# handle yields a nil pointer and a nil pointer yields a nil handle, so
# a MEOS entry answering NULL cannot become a dereference here.
out.append(
f"func (x *{go_name}) Pointer() unsafe.Pointer {{ "
f"if x == nil {{ return nil }}; return unsafe.Pointer(x._inner) }}"
)
out.append(
f"func {go_name}FromPointer(p unsafe.Pointer) *{go_name} {{ "
f"if p == nil {{ return nil }}; "
f"return &{go_name}{{_inner: (*C.{c_name})(p)}} }}"
)

# -- enums: Go type aliased to the C enum + a numeric const block --------
out.append("\n// -------------------- enums --------------------")
Expand Down
Loading