pub unsafe fn init_userdata_metatable<T>(
    state: *mut ffi::lua_State,
    metatable: c_int,
    field_getters: Option<c_int>,
    field_setters: Option<c_int>,
    methods: Option<c_int>,
) -> Result<()> {
    // Wrapper to lookup in `field_getters` first, then `methods`, ending original `__index`.
    // Used only if `field_getters` or `methods` set.
    unsafe extern "C" fn meta_index_impl(state: *mut ffi::lua_State) -> c_int {
        // stack: self, key
        ffi::luaL_checkstack(state, 2, ptr::null());

        // lookup in `field_getters` table
        if ffi::lua_isnil(state, ffi::lua_upvalueindex(2)) == 0 {
            ffi::lua_pushvalue(state, -1); // `key` arg
            if ffi::lua_rawget(state, ffi::lua_upvalueindex(2)) != ffi::LUA_TNIL {
                ffi::lua_insert(state, -3); // move function
                ffi::lua_pop(state, 1); // remove `key`
                ffi::lua_call(state, 1, 1);
                return 1;
            }
            ffi::lua_pop(state, 1); // pop the nil value
        }
        // lookup in `methods` table
        if ffi::lua_isnil(state, ffi::lua_upvalueindex(3)) == 0 {
            ffi::lua_pushvalue(state, -1); // `key` arg
            if ffi::lua_rawget(state, ffi::lua_upvalueindex(3)) != ffi::LUA_TNIL {
                ffi::lua_insert(state, -3);
                ffi::lua_pop(state, 2);
                return 1;
            }
            ffi::lua_pop(state, 1); // pop the nil value
        }

        // lookup in `__index`
        ffi::lua_pushvalue(state, ffi::lua_upvalueindex(1));
        match ffi::lua_type(state, -1) {
            ffi::LUA_TNIL => {
                ffi::lua_pop(state, 1); // pop the nil value
                let field = ffi::lua_tostring(state, -1);
                ffi::luaL_error(state, cstr!("attempt to get an unknown field '%s'"), field);
            }
            ffi::LUA_TTABLE => {
                ffi::lua_insert(state, -2);
                ffi::lua_gettable(state, -2);
            }
            ffi::LUA_TFUNCTION => {
                ffi::lua_insert(state, -3);
                ffi::lua_call(state, 2, 1);
            }
            _ => unreachable!(),
        }

        1
    }

    // Similar to `meta_index_impl`, checks `field_setters` table first, then `__newindex` metamethod.
    // Used only if `field_setters` set.
    unsafe extern "C" fn meta_newindex_impl(state: *mut ffi::lua_State) -> c_int {
        // stack: self, key, value
        ffi::luaL_checkstack(state, 2, ptr::null());

        // lookup in `field_setters` table
        ffi::lua_pushvalue(state, -2); // `key` arg
        if ffi::lua_rawget(state, ffi::lua_upvalueindex(2)) != ffi::LUA_TNIL {
            ffi::lua_remove(state, -3); // remove `key`
            ffi::lua_insert(state, -3); // move function
            ffi::lua_call(state, 2, 0);
            return 0;
        }
        ffi::lua_pop(state, 1); // pop the nil value

        // lookup in `__newindex`
        ffi::lua_pushvalue(state, ffi::lua_upvalueindex(1));
        match ffi::lua_type(state, -1) {
            ffi::LUA_TNIL => {
                ffi::lua_pop(state, 1); // pop the nil value
                let field = ffi::lua_tostring(state, -2);
                ffi::luaL_error(state, cstr!("attempt to set an unknown field '%s'"), field);
            }
            ffi::LUA_TTABLE => {
                ffi::lua_insert(state, -3);
                ffi::lua_settable(state, -3);
            }
            ffi::LUA_TFUNCTION => {
                ffi::lua_insert(state, -4);
                ffi::lua_call(state, 3, 0);
            }
            _ => unreachable!(),
        }

        0
    }

    ffi::lua_pushvalue(state, metatable);

    if field_getters.is_some() || methods.is_some() {
        push_string(state, "__index")?;
        let index_type = ffi::lua_rawget(state, -2);
        match index_type {
            ffi::LUA_TNIL | ffi::LUA_TTABLE | ffi::LUA_TFUNCTION => {
                for &idx in &[field_getters, methods] {
                    if let Some(idx) = idx {
                        ffi::lua_pushvalue(state, idx);
                    } else {
                        ffi::lua_pushnil(state);
                    }
                }
                protect_lua(state, 3, 1, |state| {
                    ffi::lua_pushcclosure(state, meta_index_impl, 3)
                })?;
            }
            _ => mlua_panic!("improper __index type {}", index_type),
        }

        rawset_field(state, -2, "__index")?;
    }

    if let Some(field_setters) = field_setters {
        push_string(state, "__newindex")?;
        let newindex_type = ffi::lua_rawget(state, -2);
        match newindex_type {
            ffi::LUA_TNIL | ffi::LUA_TTABLE | ffi::LUA_TFUNCTION => {
                ffi::lua_pushvalue(state, field_setters);
                protect_lua(state, 2, 1, |state| {
                    ffi::lua_pushcclosure(state, meta_newindex_impl, 2)
                })?;
            }
            _ => mlua_panic!("improper __newindex type {}", newindex_type),
        }

        rawset_field(state, -2, "__newindex")?;
    }

    ffi::lua_pushcfunction(state, userdata_destructor::<T>);
    rawset_field(state, -2, "__gc")?;

    ffi::lua_pushboolean(state, 0);
    rawset_field(state, -2, "__metatable")?;

    ffi::lua_pop(state, 1);

    Ok(())
}
// Populates the given table with the appropriate members to be a userdata metatable for the given type.
// This function takes the given table at the `metatable` index, and adds an appropriate `__gc` member
// to it for the given type and a `__metatable` entry to protect the table from script access.
// The function also, if given a `field_getters` or `methods` tables, will create an `__index` metamethod
// (capturing previous one) to lookup in `field_getters` first, then `methods` and falling back to the
// captured `__index` if no matches found.
// The same is also applicable for `__newindex` metamethod and `field_setters` table.
// Internally uses 9 stack spaces and does not call checkstack.
Populates the given table with the appropriate members to be a userdata metatable for the given type.
Populates the given table with the appropriate members to be a userdata metatable for the given type .
pub unsafe fn init_userdata_metatable<T>(
    state: *mut ffi::lua_State,
    metatable: c_int,
    field_getters: Option<c_int>,
    field_setters: Option<c_int>,
    methods: Option<c_int>,
) -> Result<()> {
    // Wrapper to lookup in `field_getters` first, then `methods`, ending original `__index`.
    // Used only if `field_getters` or `methods` set.
    unsafe extern "C" fn meta_index_impl(state: *mut ffi::lua_State) -> c_int {
        // stack: self, key
        ffi::luaL_checkstack(state, 2, ptr::null());
        // lookup in `field_getters` table
        if ffi::lua_isnil(state, ffi::lua_upvalueindex(2)) == 0 {
            ffi::lua_pushvalue(state, -1); // `key` arg
            if ffi::lua_rawget(state, ffi::lua_upvalueindex(2)) != ffi::LUA_TNIL {
                ffi::lua_insert(state, -3); // move function
                ffi::lua_pop(state, 1); // remove `key`
                ffi::lua_call(state, 1, 1);
                return 1;
            }
            ffi::lua_pop(state, 1); // pop the nil value
        }
        // lookup in `methods` table
        if ffi::lua_isnil(state, ffi::lua_upvalueindex(3)) == 0 {
            ffi::lua_pushvalue(state, -1); // `key` arg
            if ffi::lua_rawget(state, ffi::lua_upvalueindex(3)) != ffi::LUA_TNIL {
                ffi::lua_insert(state, -3);
                ffi::lua_pop(state, 2);
                return 1;
            }
            ffi::lua_pop(state, 1); // pop the nil value
        }
        // lookup in `__index`
        ffi::lua_pushvalue(state, ffi::lua_upvalueindex(1));
        match ffi::lua_type(state, -1) {
            ffi::LUA_TNIL => {
                ffi::lua_pop(state, 1); // pop the nil value
                let field = ffi::lua_tostring(state, -1);
                ffi::luaL_error(state, cstr!("attempt to get an unknown field '%s'"), field);
            }
            ffi::LUA_TTABLE => {
                ffi::lua_insert(state, -2);
                ffi::lua_gettable(state, -2);
            }
            ffi::LUA_TFUNCTION => {
                ffi::lua_insert(state, -3);
                ffi::lua_call(state, 2, 1);
            }
            _ => unreachable!(),
        }
        1
    }
    // Similar to `meta_index_impl`, checks `field_setters` table first, then `__newindex` metamethod.
    // Used only if `field_setters` set.
    unsafe extern "C" fn meta_newindex_impl(state: *mut ffi::lua_State) -> c_int {
        // stack: self, key, value
        ffi::luaL_checkstack(state, 2, ptr::null());
        // lookup in `field_setters` table
        ffi::lua_pushvalue(state, -2); // `key` arg
        if ffi::lua_rawget(state, ffi::lua_upvalueindex(2)) != ffi::LUA_TNIL {
            ffi::lua_remove(state, -3); // remove `key`
            ffi::lua_insert(state, -3); // move function
            ffi::lua_call(state, 2, 0);
            return 0;
        }
        ffi::lua_pop(state, 1); // pop the nil value
        // lookup in `__newindex`
        ffi::lua_pushvalue(state, ffi::lua_upvalueindex(1));
        match ffi::lua_type(state, -1) {
            ffi::LUA_TNIL => {
                ffi::lua_pop(state, 1); // pop the nil value
                let field = ffi::lua_tostring(state, -2);
                ffi::luaL_error(state, cstr!("attempt to set an unknown field '%s'"), field);
            }
            ffi::LUA_TTABLE => {
                ffi::lua_insert(state, -3);
                ffi::lua_settable(state, -3);
            }
            ffi::LUA_TFUNCTION => {
                ffi::lua_insert(state, -4);
                ffi::lua_call(state, 3, 0);
            }
            _ => unreachable!(),
        }
        0
    }
    ffi::lua_pushvalue(state, metatable);
    if field_getters.is_some() || methods.is_some() {
        push_string(state, "__index")?;
        let index_type = ffi::lua_rawget(state, -2);
        match index_type {
            ffi::LUA_TNIL | ffi::LUA_TTABLE | ffi::LUA_TFUNCTION => {
                for &idx in &[field_getters, methods] {
                    if let Some(idx) = idx {
                        ffi::lua_pushvalue(state, idx);
                    } else {
                        ffi::lua_pushnil(state);
                    }
                }
                protect_lua(state, 3, 1, |state| {
                    ffi::lua_pushcclosure(state, meta_index_impl, 3)
                })?;
            }
            _ => mlua_panic!("improper __index type {}", index_type),
        }
        rawset_field(state, -2, "__index")?;
    }
    if let Some(field_setters) = field_setters {
        push_string(state, "__newindex")?;
        let newindex_type = ffi::lua_rawget(state, -2);
        match newindex_type {
            ffi::LUA_TNIL | ffi::LUA_TTABLE | ffi::LUA_TFUNCTION => {
                ffi::lua_pushvalue(state, field_setters);
                protect_lua(state, 2, 1, |state| {
                    ffi::lua_pushcclosure(state, meta_newindex_impl, 2)
                })?;
            }
            _ => mlua_panic!("improper __newindex type {}", newindex_type),
        }
        rawset_field(state, -2, "__newindex")?;
    }
    ffi::lua_pushcfunction(state, userdata_destructor::<T>);
    rawset_field(state, -2, "__gc")?;
    ffi::lua_pushboolean(state, 0);
    rawset_field(state, -2, "__metatable")?;
    ffi::lua_pop(state, 1);
    Ok(())
}
pub unsafe fn init_userdata_metatable < T > ( state : * mut ffi :: lua_State , metatable : c_int , field_getters : Option < c_int > , field_setters : Option < c_int > , methods : Option < c_int > , ) -> Result < ( ) > { // Wrapper to lookup in `field_getters` first, then `methods`, ending original `__index`. // Used only if `field_getters` or `methods` set. unsafe extern " " fn meta_index_impl ( state : * mut ffi :: lua_State ) -> c_int { // stack: self, key ffi :: luaL_checkstack ( state , 2 , ptr :: null ( ) ) ; // lookup in `field_getters` table if ffi :: lua_isnil ( state , ffi :: lua_upvalueindex ( 2 ) ) == 0 { ffi :: lua_pushvalue ( state , - 1 ) ; // `key` arg if ffi :: lua_rawget ( state , ffi :: lua_upvalueindex ( 2 ) ) != ffi :: LUA_TNIL { ffi :: lua_insert ( state , - 3 ) ; // move function ffi :: lua_pop ( state , 1 ) ; // remove `key` ffi :: lua_call ( state , 1 , 1 ) ; return 1 ; } ffi :: lua_pop ( state , 1 ) ; // pop the nil value } // lookup in `methods` table if ffi :: lua_isnil ( state , ffi :: lua_upvalueindex ( 3 ) ) == 0 { ffi :: lua_pushvalue ( state , - 1 ) ; // `key` arg if ffi :: lua_rawget ( state , ffi :: lua_upvalueindex ( 3 ) ) != ffi :: LUA_TNIL { ffi :: lua_insert ( state , - 3 ) ; ffi :: lua_pop ( state , 2 ) ; return 1 ; } ffi :: lua_pop ( state , 1 ) ; // pop the nil value } // lookup in `__index` ffi :: lua_pushvalue ( state , ffi :: lua_upvalueindex ( 1 ) ) ; match ffi :: lua_type ( state , - 1 ) { ffi :: LUA_TNIL => { ffi :: lua_pop ( state , 1 ) ; // pop the nil value let field = ffi :: lua_tostring ( state , - 1 ) ; ffi :: luaL_error ( state , cstr ! ( " " ) , field ) ; } ffi :: LUA_TTABLE => { ffi :: lua_insert ( state , - 2 ) ; ffi :: lua_gettable ( state , - 2 ) ; } ffi :: LUA_TFUNCTION => { ffi :: lua_insert ( state , - 3 ) ; ffi :: lua_call ( state , 2 , 1 ) ; } _ => unreachable ! ( ) , } 1 } // Similar to `meta_index_impl`, checks `field_setters` table first, then `__newindex` metamethod. // Used only if `field_setters` set. unsafe extern " " fn meta_newindex_impl ( state : * mut ffi :: lua_State ) -> c_int { // stack: self, key, value ffi :: luaL_checkstack ( state , 2 , ptr :: null ( ) ) ; // lookup in `field_setters` table ffi :: lua_pushvalue ( state , - 2 ) ; // `key` arg if ffi :: lua_rawget ( state , ffi :: lua_upvalueindex ( 2 ) ) != ffi :: LUA_TNIL { ffi :: lua_remove ( state , - 3 ) ; // remove `key` ffi :: lua_insert ( state , - 3 ) ; // move function ffi :: lua_call ( state , 2 , 0 ) ; return 0 ; } ffi :: lua_pop ( state , 1 ) ; // pop the nil value // lookup in `__newindex` ffi :: lua_pushvalue ( state , ffi :: lua_upvalueindex ( 1 ) ) ; match ffi :: lua_type ( state , - 1 ) { ffi :: LUA_TNIL => { ffi :: lua_pop ( state , 1 ) ; // pop the nil value let field = ffi :: lua_tostring ( state , - 2 ) ; ffi :: luaL_error ( state , cstr ! ( " " ) , field ) ; } ffi :: LUA_TTABLE => { ffi :: lua_insert ( state , - 3 ) ; ffi :: lua_settable ( state , - 3 ) ; } ffi :: LUA_TFUNCTION => { ffi :: lua_insert ( state , - 4 ) ; ffi :: lua_call ( state , 3 , 0 ) ; } _ => unreachable ! ( ) , } 0 } ffi :: lua_pushvalue ( state , metatable ) ; if field_getters . is_some ( ) || methods . is_some ( ) { push_string ( state , " " ) ? ; let index_type = ffi :: lua_rawget ( state , - 2 ) ; match index_type { ffi :: LUA_TNIL | ffi :: LUA_TTABLE | ffi :: LUA_TFUNCTION => { for & idx in & [ field_getters , methods ] { if let Some ( idx ) = idx { ffi :: lua_pushvalue ( state , idx ) ; } else { ffi :: lua_pushnil ( state ) ; } } protect_lua ( state , 3 , 1 , | state | { ffi :: lua_pushcclosure ( state , meta_index_impl , 3 ) } ) ? ; } _ => mlua_panic ! ( " " index_type ) , } rawset_field ( state , - 2 , " " ) ? ; } if let Some ( field_setters ) = field_setters { push_string ( state , " " ) ? ; let newindex_type = ffi :: lua_rawget ( state , - 2 ) ; match newindex_type { ffi :: LUA_TNIL | ffi :: LUA_TTABLE | ffi :: LUA_TFUNCTION => { ffi :: lua_pushvalue ( state , field_setters ) ; protect_lua ( state , 2 , 1 , | state | { ffi :: lua_pushcclosure ( state , meta_newindex_impl , 2 ) } ) ? ; } _ => mlua_panic ! ( " " newindex_type ) , } rawset_field ( state , - 2 , " " ) ? ; } ffi :: lua_pushcfunction ( state , userdata_destructor :: < T > ) ; rawset_field ( state , - 2 , " " ) ? ; ffi :: lua_pushboolean ( state , 0 ) ; rawset_field ( state , - 2 , " " ) ? ; ffi :: lua_pop ( state , 1 ) ; Ok ( ( ) ) }
Populates the given table with the appropriate members to be a userdata metatable for the given type.
Populates the given table with the appropriate members to be a userdata metatable for the given type .
state
*mut ffi::lua_State
metatable
c_int
field_getters
Option<c_int>
field_setters
Option<c_int>
methods
Option<c_int>
state
*mut ffi::lua_State
metatable
c_int
field_getters
Option<c_int>
field_setters
Option<c_int>
methods
Option<c_int>