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  }