+57,
-0
1@@ -15,6 +15,8 @@ This library provides Go bindings to y-crdt's Yjs-compatible CRDT implementation
2 - **Updates** - State synchronization between peers
3 - **Undo/Redo** - Operation history management
4
5+**Resource Management:** All types (`Doc`, `Text`, `Array`, `Map`, `XmlFragment`, etc.) require explicit cleanup. Always use `defer obj.Destroy()` when creating these objects to prevent memory leaks. See the Quick Start example below.
6+
7 ## Installation
8
9 ```bash
10@@ -124,6 +126,61 @@ func main() {
11 }
12 ```
13
14+## Convenience Features
15+
16+### Typed Map Getters
17+
18+Get typed values from maps without manual type checking:
19+
20+```go
21+// Instead of verbose Output handling:
22+// out, _ := m.Get(txn, "name")
23+// defer out.Destroy()
24+// str, _ := out.String()
25+
26+// Use convenience getters:
27+name, _ := m.GetString(txn, "name")
28+age, _ := m.GetInt(txn, "age")
29+pi, _ := m.GetFloat(txn, "pi")
30+active, _ := m.GetBool(txn, "active")
31+```
32+
33+### Map/Array Iteration
34+
35+Iterate with callbacks instead of manual iterator management:
36+
37+```go
38+// Map iteration
39+err = m.ForEach(txn, func(key string, value *ygo.Output) error {
40+ // Process each entry
41+ // Return error to stop iteration early
42+ return nil
43+})
44+
45+// Array iteration
46+err = arr.ForEach(txn, func(index uint32, value *ygo.Output) error {
47+ // Process each element
48+ return nil
49+})
50+```
51+
52+### Map Input from Go Maps
53+
54+Create inputs from Go maps instead of parallel slices:
55+
56+```go
57+// Old: parallel slices (error-prone)
58+// ygo.YMap([]string{"name", "age"}, []ygo.Input{ygo.String("Alice"), ygo.Int(30)})
59+
60+// New: Go map syntax
61+data := map[string]ygo.Input{
62+ "name": ygo.String("Alice"),
63+ "age": ygo.Int(30),
64+}
65+input, _ := ygo.MapInput(data)
66+m.Insert(txn, "user", input)
67+```
68+
69 ## Serialization
70
71 Documents support standard Go binary marshaling:
M
array.go
+31,
-3
1@@ -8,7 +8,6 @@ import "C"
2 import (
3 "encoding/json"
4 "fmt"
5- "runtime"
6 "unsafe"
7 )
8
9@@ -31,13 +30,11 @@ func (d *Doc) GetArray(name string) (*Array, error) {
10 }
11
12 a := &Array{branch: branch}
13- runtime.SetFinalizer(a, (*Array).Destroy)
14 return a, nil
15 }
16
17 // Destroy releases resources.
18 func (a *Array) Destroy() {
19- runtime.SetFinalizer(a, nil)
20 }
21
22 // Len returns the number of elements.
23@@ -142,6 +139,37 @@ func (a *Array) Iter(txn *Transaction) (*ArrayIter, error) {
24 return &ArrayIter{ptr: ptr}, nil
25 }
26
27+// ForEach iterates over all elements in the array, calling fn for each element.
28+// The index is passed as the first argument to fn.
29+// If fn returns an error, iteration stops and the error is returned.
30+// The Output is automatically destroyed after fn returns.
31+func (a *Array) ForEach(txn *Transaction, fn func(index uint32, value *Output) error) error {
32+ iter, err := a.Iter(txn)
33+ if err != nil {
34+ return err
35+ }
36+ defer iter.Destroy()
37+
38+ var index uint32
39+ for {
40+ out, err := iter.Next()
41+ if err != nil {
42+ return err
43+ }
44+ if out == nil {
45+ break
46+ }
47+
48+ if err := fn(index, out); err != nil {
49+ out.Destroy()
50+ return err
51+ }
52+ out.Destroy()
53+ index++
54+ }
55+ return nil
56+}
57+
58 // ArrayIter iterates over array elements.
59 type ArrayIter struct {
60 ptr *C.YArrayIter
+380,
-0
1@@ -0,0 +1,380 @@
2+package ygo_test
3+
4+import (
5+ "testing"
6+
7+ "github.com/BTBurke/ygo"
8+)
9+
10+func TestMapGetString(t *testing.T) {
11+ doc, err := ygo.NewDoc()
12+ if err != nil {
13+ t.Fatalf("failed to create doc: %v", err)
14+ }
15+ defer doc.Destroy()
16+
17+ m, err := doc.GetMap("test")
18+ if err != nil {
19+ t.Fatalf("failed to get map: %v", err)
20+ }
21+ defer m.Destroy()
22+
23+ // Insert test data
24+ err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
25+ m.Insert(txn, "name", ygo.String("Alice"))
26+ return nil
27+ })
28+ if err != nil {
29+ t.Fatalf("transaction failed: %v", err)
30+ }
31+
32+ // Test GetString
33+ var name string
34+ err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
35+ var err error
36+ name, err = m.GetString(txn, "name")
37+ return err
38+ })
39+ if err != nil {
40+ t.Fatalf("GetString failed: %v", err)
41+ }
42+ if name != "Alice" {
43+ t.Errorf("expected Alice, got %s", name)
44+ }
45+}
46+
47+func TestMapGetInt(t *testing.T) {
48+ doc, err := ygo.NewDoc()
49+ if err != nil {
50+ t.Fatalf("failed to create doc: %v", err)
51+ }
52+ defer doc.Destroy()
53+
54+ m, err := doc.GetMap("test")
55+ if err != nil {
56+ t.Fatalf("failed to get map: %v", err)
57+ }
58+ defer m.Destroy()
59+
60+ // Insert test data
61+ err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
62+ m.Insert(txn, "age", ygo.Int(30))
63+ return nil
64+ })
65+ if err != nil {
66+ t.Fatalf("transaction failed: %v", err)
67+ }
68+
69+ // Test GetInt
70+ var age int64
71+ err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
72+ var err error
73+ age, err = m.GetInt(txn, "age")
74+ return err
75+ })
76+ if err != nil {
77+ t.Fatalf("GetInt failed: %v", err)
78+ }
79+ if age != 30 {
80+ t.Errorf("expected 30, got %d", age)
81+ }
82+}
83+
84+func TestMapGetFloat(t *testing.T) {
85+ doc, err := ygo.NewDoc()
86+ if err != nil {
87+ t.Fatalf("failed to create doc: %v", err)
88+ }
89+ defer doc.Destroy()
90+
91+ m, err := doc.GetMap("test")
92+ if err != nil {
93+ t.Fatalf("failed to get map: %v", err)
94+ }
95+ defer m.Destroy()
96+
97+ // Insert test data
98+ err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
99+ m.Insert(txn, "pi", ygo.Float(3.14))
100+ return nil
101+ })
102+ if err != nil {
103+ t.Fatalf("transaction failed: %v", err)
104+ }
105+
106+ // Test GetFloat
107+ var pi float64
108+ err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
109+ var err error
110+ pi, err = m.GetFloat(txn, "pi")
111+ return err
112+ })
113+ if err != nil {
114+ t.Fatalf("GetFloat failed: %v", err)
115+ }
116+ if pi != 3.14 {
117+ t.Errorf("expected 3.14, got %f", pi)
118+ }
119+}
120+
121+func TestMapGetBool(t *testing.T) {
122+ doc, err := ygo.NewDoc()
123+ if err != nil {
124+ t.Fatalf("failed to create doc: %v", err)
125+ }
126+ defer doc.Destroy()
127+
128+ m, err := doc.GetMap("test")
129+ if err != nil {
130+ t.Fatalf("failed to get map: %v", err)
131+ }
132+ defer m.Destroy()
133+
134+ // Insert test data
135+ err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
136+ m.Insert(txn, "active", ygo.Bool(true))
137+ return nil
138+ })
139+ if err != nil {
140+ t.Fatalf("transaction failed: %v", err)
141+ }
142+
143+ // Test GetBool
144+ var active bool
145+ err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
146+ var err error
147+ active, err = m.GetBool(txn, "active")
148+ return err
149+ })
150+ if err != nil {
151+ t.Fatalf("GetBool failed: %v", err)
152+ }
153+ if !active {
154+ t.Errorf("expected true, got %v", active)
155+ }
156+}
157+
158+func TestMapForEach(t *testing.T) {
159+ doc, err := ygo.NewDoc()
160+ if err != nil {
161+ t.Fatalf("failed to create doc: %v", err)
162+ }
163+ defer doc.Destroy()
164+
165+ m, err := doc.GetMap("test")
166+ if err != nil {
167+ t.Fatalf("failed to get map: %v", err)
168+ }
169+ defer m.Destroy()
170+
171+ // Insert test data
172+ err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
173+ m.Insert(txn, "a", ygo.String("1"))
174+ m.Insert(txn, "b", ygo.String("2"))
175+ m.Insert(txn, "c", ygo.String("3"))
176+ return nil
177+ })
178+ if err != nil {
179+ t.Fatalf("transaction failed: %v", err)
180+ }
181+
182+ // Test ForEach
183+ var count int
184+ err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
185+ return m.ForEach(txn, func(key string, value *ygo.Output) error {
186+ count++
187+ return nil
188+ })
189+ })
190+ if err != nil {
191+ t.Fatalf("ForEach failed: %v", err)
192+ }
193+ if count != 3 {
194+ t.Errorf("expected 3 entries, got %d", count)
195+ }
196+}
197+
198+func TestMapForEachEarlyExit(t *testing.T) {
199+ doc, err := ygo.NewDoc()
200+ if err != nil {
201+ t.Fatalf("failed to create doc: %v", err)
202+ }
203+ defer doc.Destroy()
204+
205+ m, err := doc.GetMap("test")
206+ if err != nil {
207+ t.Fatalf("failed to get map: %v", err)
208+ }
209+ defer m.Destroy()
210+
211+ // Insert test data
212+ err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
213+ m.Insert(txn, "a", ygo.String("1"))
214+ m.Insert(txn, "b", ygo.String("2"))
215+ m.Insert(txn, "c", ygo.String("3"))
216+ return nil
217+ })
218+ if err != nil {
219+ t.Fatalf("transaction failed: %v", err)
220+ }
221+
222+ // Test ForEach with early exit
223+ var count int
224+ testErr := ygo.ErrKeyNotFound // Just use any error for testing
225+ err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
226+ return m.ForEach(txn, func(key string, value *ygo.Output) error {
227+ count++
228+ if count >= 2 {
229+ return testErr
230+ }
231+ return nil
232+ })
233+ })
234+ if err != testErr {
235+ t.Fatalf("expected ForEach to return test error, got: %v", err)
236+ }
237+ if count != 2 {
238+ t.Errorf("expected iteration to stop at 2, got %d", count)
239+ }
240+}
241+
242+func TestArrayForEach(t *testing.T) {
243+ doc, err := ygo.NewDoc()
244+ if err != nil {
245+ t.Fatalf("failed to create doc: %v", err)
246+ }
247+ defer doc.Destroy()
248+
249+ arr, err := doc.GetArray("test")
250+ if err != nil {
251+ t.Fatalf("failed to get array: %v", err)
252+ }
253+ defer arr.Destroy()
254+
255+ // Insert test data
256+ err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
257+ arr.Push(txn, ygo.Int(10))
258+ arr.Push(txn, ygo.Int(20))
259+ arr.Push(txn, ygo.Int(30))
260+ return nil
261+ })
262+ if err != nil {
263+ t.Fatalf("transaction failed: %v", err)
264+ }
265+
266+ // Test ForEach
267+ var sum int64
268+ err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
269+ return arr.ForEach(txn, func(index uint32, value *ygo.Output) error {
270+ if v, ok := value.Int(); ok {
271+ sum += v
272+ }
273+ return nil
274+ })
275+ })
276+ if err != nil {
277+ t.Fatalf("ForEach failed: %v", err)
278+ }
279+ if sum != 60 {
280+ t.Errorf("expected sum 60, got %d", sum)
281+ }
282+}
283+
284+func TestMapInput(t *testing.T) {
285+ // Test MapInput with data
286+ data := map[string]ygo.Input{
287+ "name": ygo.String("Alice"),
288+ "age": ygo.Int(30),
289+ }
290+ input, err := ygo.MapInput(data)
291+ if err != nil {
292+ t.Fatalf("MapInput failed: %v", err)
293+ }
294+
295+ doc, err := ygo.NewDoc()
296+ if err != nil {
297+ t.Fatalf("failed to create doc: %v", err)
298+ }
299+ defer doc.Destroy()
300+
301+ m, err := doc.GetMap("test")
302+ if err != nil {
303+ t.Fatalf("failed to get map: %v", err)
304+ }
305+ defer m.Destroy()
306+
307+ // Insert the map input
308+ err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
309+ return m.Insert(txn, "data", input)
310+ })
311+ if err != nil {
312+ t.Fatalf("transaction failed: %v", err)
313+ }
314+
315+ // Verify we can read it back
316+ var name string
317+ err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
318+ dataMap, err := m.GetNestedMap(txn, "data")
319+ if err != nil {
320+ return err
321+ }
322+ defer dataMap.Destroy()
323+ name, err = dataMap.GetString(txn, "name")
324+ return err
325+ })
326+ if err != nil {
327+ t.Fatalf("GetNestedMap failed: %v", err)
328+ }
329+ if name != "Alice" {
330+ t.Errorf("expected Alice, got %s", name)
331+ }
332+}
333+
334+func TestJSONObject(t *testing.T) {
335+ // Test JSONObject with data
336+ data := map[string]ygo.Input{
337+ "name": ygo.String("Bob"),
338+ "age": ygo.Int(25),
339+ }
340+ input, err := ygo.JSONObject(data)
341+ if err != nil {
342+ t.Fatalf("JSONObject failed: %v", err)
343+ }
344+
345+ doc, err := ygo.NewDoc()
346+ if err != nil {
347+ t.Fatalf("failed to create doc: %v", err)
348+ }
349+ defer doc.Destroy()
350+
351+ m, err := doc.GetMap("test")
352+ if err != nil {
353+ t.Fatalf("failed to get map: %v", err)
354+ }
355+ defer m.Destroy()
356+
357+ // Insert the JSON object input
358+ err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
359+ return m.Insert(txn, "data", input)
360+ })
361+ if err != nil {
362+ t.Fatalf("transaction failed: %v", err)
363+ }
364+
365+ // Verify we can read it back as a JSON map
366+ err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
367+ out, err := m.Get(txn, "data")
368+ if err != nil {
369+ return err
370+ }
371+ defer out.Destroy()
372+
373+ if out.Tag() != ygo.TagJSONMap {
374+ t.Errorf("expected TagJSONMap, got %v", out.Tag())
375+ }
376+ return nil
377+ })
378+ if err != nil {
379+ t.Fatalf("Get failed: %v", err)
380+ }
381+}
+1,
-20
1@@ -9,7 +9,6 @@ import (
2 "encoding"
3 "encoding/json"
4 "fmt"
5- "runtime"
6 "unsafe"
7
8 "github.com/BTBurke/ygo/sync"
9@@ -84,7 +83,6 @@ func NewDoc() (*Doc, error) {
10 if d.ptr == nil {
11 return nil, fmt.Errorf("failed to create document: C.ydoc_new() returned nil")
12 }
13- runtime.SetFinalizer(d, (*Doc).Destroy)
14 return d, nil
15 }
16
17@@ -105,22 +103,6 @@ func NewDocWithOptions(opts DocOptions) (*Doc, error) {
18 return nil, fmt.Errorf("failed to create document with options: C.ydoc_new_with_options() returned nil")
19 }
20
21- runtime.SetFinalizer(d, (*Doc).Destroy)
22- return d, nil
23-}
24-
25-// NewDocWithSync creates a new document with a sync client attached.
26-// The returned document will be synchronized with the sync server.
27-func NewDocWithSync(client *sync.SyncClient, opts ...DocOption) (*Doc, error) {
28- docOpts := DefaultOptions()
29- for _, opt := range opts {
30- opt(&docOpts)
31- }
32- d, err := NewDocWithOptions(docOpts)
33- if err != nil {
34- return nil, err
35- }
36- d.sync = client
37 return d, nil
38 }
39
40@@ -136,7 +118,6 @@ func (d *Doc) Clone() (*Doc, error) {
41 if cloned.ptr == nil {
42 return nil, fmt.Errorf("failed to clone document: C.ydoc_clone() returned nil")
43 }
44- runtime.SetFinalizer(cloned, (*Doc).Destroy)
45 return cloned, nil
46 }
47
48@@ -259,6 +240,7 @@ func (d *Doc) AutoLoad() bool {
49 // If a sync client is attached, it will send any pending updates,
50 // gracefully disconnect from the server, then destroy the document.
51 // Safe to call from within the OnUpdate callback.
52+// Callers must call Destroy() explicitly when done with the document.
53 func (d *Doc) Destroy() {
54 // Close sync connection first (sends pending updates)
55 if d.sync != nil {
56@@ -269,7 +251,6 @@ func (d *Doc) Destroy() {
57 if d.ptr != nil {
58 C.ydoc_destroy(d.ptr)
59 d.ptr = nil
60- runtime.SetFinalizer(d, nil)
61 }
62 }
63
M
input.go
+41,
-0
1@@ -170,6 +170,47 @@ func YMap(keys []string, values []Input) (Input, error) {
2 return result, nil
3 }
4
5+// MapInput creates a YMap shared type input from a Go map.
6+// Usage: ygo.MapInput(map[string]ygo.Input{"name": ygo.String("Alice"), "age": ygo.Int(30)})
7+//
8+// Note: The iteration order of Go maps is not guaranteed, so the resulting
9+// YMap may have keys in any order.
10+func MapInput(items map[string]Input) (Input, error) {
11+ if len(items) == 0 {
12+ return YMap(nil, nil)
13+ }
14+
15+ // Extract keys and values
16+ keys := make([]string, 0, len(items))
17+ values := make([]Input, 0, len(items))
18+ for k, v := range items {
19+ keys = append(keys, k)
20+ values = append(values, v)
21+ }
22+
23+ return YMap(keys, values)
24+}
25+
26+// JSONObject creates a JSON map input from a Go map.
27+// Usage: ygo.JSONObject(map[string]ygo.Input{"name": ygo.String("Alice"), "age": ygo.Int(30)})
28+//
29+// Note: The iteration order of Go maps is not guaranteed, so the resulting
30+// JSON object may have keys in any order.
31+func JSONObject(items map[string]Input) (Input, error) {
32+ if len(items) == 0 {
33+ return JSONMap(nil, nil)
34+ }
35+
36+ keys := make([]string, 0, len(items))
37+ values := make([]Input, 0, len(items))
38+ for k, v := range items {
39+ keys = append(keys, k)
40+ values = append(values, v)
41+ }
42+
43+ return JSONMap(keys, values)
44+}
45+
46 // YText creates a YText shared type input with initial content.
47 func YText(initial string) Input {
48 cStr := C.CString(initial)
M
map.go
+100,
-3
1@@ -8,7 +8,6 @@ import "C"
2 import (
3 "encoding/json"
4 "fmt"
5- "runtime"
6 "unsafe"
7 )
8
9@@ -31,13 +30,11 @@ func (d *Doc) GetMap(name string) (*Map, error) {
10 }
11
12 m := &Map{branch: branch}
13- runtime.SetFinalizer(m, (*Map).Destroy)
14 return m, nil
15 }
16
17 // Destroy releases resources.
18 func (m *Map) Destroy() {
19- runtime.SetFinalizer(m, nil)
20 }
21
22 // Len returns the number of entries.
23@@ -166,6 +163,78 @@ func (m *Map) GetNestedArray(txn *Transaction, key string) (*Array, error) {
24 return &Array{branch: branch}, nil
25 }
26
27+// GetString retrieves a string value by key.
28+// Returns ErrKeyNotFound if key doesn't exist.
29+// Returns error if value is not a string.
30+func (m *Map) GetString(txn *Transaction, key string) (string, error) {
31+ out, err := m.Get(txn, key)
32+ if err != nil {
33+ return "", err
34+ }
35+ defer out.Destroy()
36+
37+ str, ok := out.String()
38+ if !ok {
39+ return "", fmt.Errorf("value at key %q is not a string (got %v)", key, out.Tag())
40+ }
41+ return str, nil
42+}
43+
44+// GetInt retrieves an integer value by key.
45+// Returns ErrKeyNotFound if key doesn't exist.
46+// Returns error if value is not an integer or float.
47+func (m *Map) GetInt(txn *Transaction, key string) (int64, error) {
48+ out, err := m.Get(txn, key)
49+ if err != nil {
50+ return 0, err
51+ }
52+ defer out.Destroy()
53+
54+ if val, ok := out.Int(); ok {
55+ return val, nil
56+ }
57+ if val, ok := out.Float(); ok {
58+ return int64(val), nil
59+ }
60+ return 0, fmt.Errorf("value at key %q is not a number (got %v)", key, out.Tag())
61+}
62+
63+// GetFloat retrieves a float value by key.
64+// Returns ErrKeyNotFound if key doesn't exist.
65+// Returns error if value is not a number.
66+func (m *Map) GetFloat(txn *Transaction, key string) (float64, error) {
67+ out, err := m.Get(txn, key)
68+ if err != nil {
69+ return 0, err
70+ }
71+ defer out.Destroy()
72+
73+ if val, ok := out.Float(); ok {
74+ return val, nil
75+ }
76+ if val, ok := out.Int(); ok {
77+ return float64(val), nil
78+ }
79+ return 0, fmt.Errorf("value at key %q is not a number (got %v)", key, out.Tag())
80+}
81+
82+// GetBool retrieves a boolean value by key.
83+// Returns ErrKeyNotFound if key doesn't exist.
84+// Returns error if value is not a boolean.
85+func (m *Map) GetBool(txn *Transaction, key string) (bool, error) {
86+ out, err := m.Get(txn, key)
87+ if err != nil {
88+ return false, err
89+ }
90+ defer out.Destroy()
91+
92+ val, ok := out.Bool()
93+ if !ok {
94+ return false, fmt.Errorf("value at key %q is not a bool (got %v)", key, out.Tag())
95+ }
96+ return val, nil
97+}
98+
99 // MapEntry represents a key-value pair from a map.
100 type MapEntry struct {
101 Key string
102@@ -221,6 +290,34 @@ func (m *Map) Iter(txn *Transaction) (*MapIter, error) {
103 return &MapIter{ptr: ptr}, nil
104 }
105
106+// ForEach iterates over all entries in the map, calling fn for each key-value pair.
107+// If fn returns an error, iteration stops and the error is returned.
108+// The Output is automatically destroyed after fn returns.
109+func (m *Map) ForEach(txn *Transaction, fn func(key string, value *Output) error) error {
110+ iter, err := m.Iter(txn)
111+ if err != nil {
112+ return err
113+ }
114+ defer iter.Destroy()
115+
116+ for {
117+ entry, err := iter.Next()
118+ if err != nil {
119+ return err
120+ }
121+ if entry == nil {
122+ break
123+ }
124+
125+ if err := fn(entry.Key, entry.Value); err != nil {
126+ entry.Value.Destroy()
127+ return err
128+ }
129+ entry.Value.Destroy()
130+ }
131+ return nil
132+}
133+
134 // MarshalJSONWithTxn implements JSON marshaling for Map.
135 // Returns a JSON object with string keys and JSON values.
136 func (m *Map) MarshalJSONWithTxn(txn *Transaction) ([]byte, error) {
+0,
-5
1@@ -6,7 +6,6 @@ package ygo
2 import "C"
3 import (
4 "fmt"
5- "runtime"
6 "unsafe"
7 )
8
9@@ -50,7 +49,6 @@ func NewStickyIndexFromIndex(t interface{ Branch() unsafe.Pointer }, txn *Transa
10 }
11
12 si := &StickyIndex{ptr: ptr}
13- runtime.SetFinalizer(si, (*StickyIndex).Destroy)
14 return si, nil
15 }
16
17@@ -59,7 +57,6 @@ func (si *StickyIndex) Destroy() {
18 if si.ptr != nil {
19 C.ysticky_index_destroy(si.ptr)
20 si.ptr = nil
21- runtime.SetFinalizer(si, nil)
22 }
23 }
24
25@@ -101,7 +98,6 @@ func DecodeStickyIndex(data []byte) (*StickyIndex, error) {
26 }
27
28 si := &StickyIndex{ptr: ptr}
29- runtime.SetFinalizer(si, (*StickyIndex).Destroy)
30 return si, nil
31 }
32
33@@ -124,7 +120,6 @@ func ParseStickyIndexJSON(jsonStr string) (*StickyIndex, error) {
34 }
35
36 si := &StickyIndex{ptr: ptr}
37- runtime.SetFinalizer(si, (*StickyIndex).Destroy)
38 return si, nil
39 }
40
M
text.go
+0,
-3
1@@ -8,7 +8,6 @@ import "C"
2 import (
3 "encoding/json"
4 "fmt"
5- "runtime"
6 "unsafe"
7 )
8
9@@ -31,14 +30,12 @@ func (d *Doc) GetText(name string) (*Text, error) {
10 }
11
12 t := &Text{branch: branch}
13- runtime.SetFinalizer(t, (*Text).Destroy)
14 return t, nil
15 }
16
17 // Destroy releases resources (does not delete the text from document).
18 func (t *Text) Destroy() {
19 // Text is managed by document, no explicit destroy needed
20- runtime.SetFinalizer(t, nil)
21 }
22
23 // Len returns the length of the text in UTF code units (based on doc encoding).
+0,
-3
1@@ -7,7 +7,6 @@ package ygo
2 import "C"
3 import (
4 "fmt"
5- "runtime"
6 "unsafe"
7 )
8
9@@ -125,7 +124,6 @@ func (t *Transaction) Commit() {
10 if t.ptr != nil {
11 C.ytransaction_commit(t.ptr)
12 t.ptr = nil
13- runtime.SetFinalizer(t, nil)
14 }
15 }
16
17@@ -135,7 +133,6 @@ func (t *Transaction) Rollback() {
18 if t.ptr != nil {
19 C.ytransaction_commit(t.ptr) // yffi uses commit to end, even for rollback
20 t.ptr = nil
21- runtime.SetFinalizer(t, nil)
22 }
23 }
24
M
undo.go
+0,
-3
1@@ -7,7 +7,6 @@ package ygo
2 import "C"
3 import (
4 "fmt"
5- "runtime"
6 "unsafe"
7 )
8
9@@ -43,7 +42,6 @@ func NewUndoManager(doc *Doc, opts *UndoManagerOptions) (*UndoManager, error) {
10 }
11
12 m := &UndoManager{ptr: ptr}
13- runtime.SetFinalizer(m, (*UndoManager).Destroy)
14 return m, nil
15 }
16
17@@ -52,7 +50,6 @@ func (m *UndoManager) Destroy() {
18 if m.ptr != nil {
19 C.yundo_manager_destroy(m.ptr)
20 m.ptr = nil
21- runtime.SetFinalizer(m, nil)
22 }
23 }
24
M
weak.go
+0,
-3
1@@ -7,7 +7,6 @@ package ygo
2 import "C"
3 import (
4 "fmt"
5- "runtime"
6 "unsafe"
7 )
8
9@@ -57,7 +56,6 @@ func (w *Weak) Destroy() {
10 if w.ptr != nil {
11 C.yweak_destroy(w.ptr)
12 w.ptr = nil
13- runtime.SetFinalizer(w, nil)
14 }
15 }
16
17@@ -213,7 +211,6 @@ func (m *Map) LinkMap(txn *Transaction, key string) (*Weak, error) {
18 }
19
20 w := &Weak{ptr: ptr}
21- runtime.SetFinalizer(w, (*Weak).Destroy)
22 return w, nil
23 }
24
M
xml.go
+5,
-9
1@@ -8,7 +8,6 @@ import "C"
2 import (
3 "encoding/json"
4 "fmt"
5- "runtime"
6 "unsafe"
7 )
8
9@@ -31,13 +30,11 @@ func (d *Doc) GetXmlFragment(name string) (*XmlFragment, error) {
10 }
11
12 f := &XmlFragment{branch: branch}
13- runtime.SetFinalizer(f, (*XmlFragment).Destroy)
14 return f, nil
15 }
16
17 // Destroy releases resources.
18 func (f *XmlFragment) Destroy() {
19- runtime.SetFinalizer(f, nil)
20 }
21
22 // InsertElement creates and inserts an XML element at index.
23@@ -60,7 +57,7 @@ func (f *XmlFragment) InsertElement(txn *Transaction, index uint32, tag string)
24 }
25
26 e := &XmlElement{branch: branch}
27- runtime.SetFinalizer(e, (*XmlElement).Destroy)
28+ // REMOVED: runtime.SetFinalizer
29 return e, nil
30 }
31
32@@ -82,7 +79,7 @@ func (f *XmlFragment) InsertText(txn *Transaction, index uint32) (*XmlText, erro
33 }
34
35 t := &XmlText{branch: branch}
36- runtime.SetFinalizer(t, (*XmlText).Destroy)
37+ // REMOVED: runtime.SetFinalizer
38 return t, nil
39 }
40
41@@ -93,7 +90,7 @@ type XmlElement struct {
42
43 // Destroy releases resources.
44 func (e *XmlElement) Destroy() {
45- runtime.SetFinalizer(e, nil)
46+ // REMOVED: runtime.SetFinalizer
47 }
48
49 // Tag returns the element's tag name.
50@@ -182,7 +179,6 @@ func (e *XmlElement) InsertElement(txn *Transaction, index uint32, tag string) (
51 }
52
53 elem := &XmlElement{branch: branch}
54- runtime.SetFinalizer(elem, (*XmlElement).Destroy)
55 return elem, nil
56 }
57
58@@ -204,7 +200,7 @@ func (e *XmlElement) InsertText(txn *Transaction, index uint32) (*XmlText, error
59 }
60
61 t := &XmlText{branch: branch}
62- runtime.SetFinalizer(t, (*XmlText).Destroy)
63+ // REMOVED: runtime.SetFinalizer
64 return t, nil
65 }
66
67@@ -230,7 +226,7 @@ type XmlText struct {
68
69 // Destroy releases resources.
70 func (t *XmlText) Destroy() {
71- runtime.SetFinalizer(t, nil)
72+ // REMOVED: runtime.SetFinalizer
73 }
74
75 // Len returns the text length.