github.com/arnodel/golua@v0.0.0-20230215163904-e0b5347eaaa1/runtime/userdata.go (about) 1 package runtime 2 3 import "github.com/arnodel/golua/runtime/internal/luagc" 4 5 type ResourceReleaser interface { 6 ReleaseResources() 7 } 8 9 func releaseResources(refs []luagc.Value) { 10 for _, r := range refs { 11 if rr, ok := r.(ResourceReleaser); ok { 12 rr.ReleaseResources() 13 } 14 } 15 } 16 17 type UserDataResourceReleaser interface { 18 ReleaseResources(d *UserData) 19 } 20 21 // A UserData is a Go value of any type wrapped to be used as a Lua value. It 22 // has a metatable which may allow Lua code to interact with it. 23 type UserData struct { 24 value interface{} 25 meta *Table 26 } 27 28 var _ ResourceReleaser = (*UserData)(nil) 29 30 // NewUserData returns a new UserData pointer for the value v, giving it meta as 31 // a metatable. This does not register a GC finalizer because access to a 32 // runtime is needed for that. 33 func NewUserData(v interface{}, meta *Table) *UserData { 34 return &UserData{value: v, meta: meta} 35 } 36 37 // Value returns the userdata's value. 38 func (d *UserData) Value() interface{} { 39 return d.value 40 } 41 42 // Metatable returns the userdata's metatable. 43 func (d *UserData) Metatable() *Table { 44 return d.meta 45 } 46 47 // SetMetatable sets d's metatable to m. 48 func (d *UserData) SetMetatable(m *Table) { 49 d.meta = m 50 } 51 52 var _ luagc.Value = (*UserData)(nil) 53 54 func (d *UserData) Key() luagc.Key { 55 return d.value 56 } 57 58 func (d *UserData) Clone() luagc.Value { 59 clone := new(UserData) 60 *clone = *d 61 return clone 62 } 63 64 // HasFinalizer returns true if the user data has finalizing code (either via 65 // __gc metamethod or the value needs prefinalization). 66 func (d *UserData) MarkFlags() (flags luagc.MarkFlags) { 67 _, ok := d.value.(UserDataResourceReleaser) 68 if ok { 69 flags |= luagc.Release 70 } 71 if !RawGet(d.meta, MetaFieldGcValue).IsNil() { 72 flags |= luagc.Finalize 73 } 74 return flags 75 } 76 77 // Prefinalizer runs the value's prefinalize 78 func (d *UserData) ReleaseResources() { 79 if pf, ok := d.value.(UserDataResourceReleaser); ok { 80 pf.ReleaseResources(d) 81 } 82 } 83 84 // NewUserDataValue creates a Value containing the user data with the given Go 85 // value and metatable. It also registers a GC finalizer if the metadata has a 86 // __gc field. 87 func (r *Runtime) NewUserDataValue(iface interface{}, meta *Table) Value { 88 udata := NewUserData(iface, meta) 89 r.addFinalizer(udata, udata.MarkFlags()) 90 return UserDataValue(udata) 91 } 92 93 // 94 // LightUserData 95 // 96 97 // A LightUserData is some Go value of unspecified type wrapped to be used as a 98 // lua Value. 99 type LightUserData struct { 100 Data interface{} 101 }