{"action":"created","issue":{"url":"https://api.github.com/repos/jcmoyer/rust-lua53/issues/67","repository_url":"https://api.github.com/repos/jcmoyer/rust-lua53","labels_url":"https://api.github.com/repos/jcmoyer/rust-lua53/issues/67/labels{/name}","comments_url":"https://api.github.com/repos/jcmoyer/rust-lua53/issues/67/comments","events_url":"https://api.github.com/repos/jcmoyer/rust-lua53/issues/67/events","html_url":"https://github.com/jcmoyer/rust-lua53/issues/67","id":174582121,"number":67,"title":"Macro overrides for customizable Lua compile-time options","user":{"login":"sagebind","id":2192863,"avatar_url":"https://avatars.githubusercontent.com/u/2192863?v=3","gravatar_id":"","url":"https://api.github.com/users/sagebind","html_url":"https://github.com/sagebind","followers_url":"https://api.github.com/users/sagebind/followers","following_url":"https://api.github.com/users/sagebind/following{/other_user}","gists_url":"https://api.github.com/users/sagebind/gists{/gist_id}","starred_url":"https://api.github.com/users/sagebind/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sagebind/subscriptions","organizations_url":"https://api.github.com/users/sagebind/orgs","repos_url":"https://api.github.com/users/sagebind/repos","events_url":"https://api.github.com/users/sagebind/events{/privacy}","received_events_url":"https://api.github.com/users/sagebind/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/jcmoyer/rust-lua53/labels/discussion","name":"discussion","color":"5319e7"}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":3,"created_at":"2016-09-01T17:34:52Z","updated_at":"2016-09-02T22:57:24Z","closed_at":null,"body":"_(Please forgive me for the wall of text. It is an interesting read, I promise.)_\r\n\r\nI am currently investigating into using this crate in a multithreaded manner. In order to do so, I need to override the Lua definitions for the `lua_lock()` and `lua_unlock()` macros, which brought up the larger question of how these macros can be overridden. Since Lua is meant to be customizable for many different uses, I think this is an important discussion to have and something we should try to solve.\r\n\r\nThe main issue as to why this is not easy is because Lua is compiled _before_ this crate, and not _with_ it. C and Rust can't be mixed, so this isn't something we can solve to my knowledge.\r\n\r\nI see three options currently, though I'd love to see if anyone else has better ideas than these admittedly poor options:\r\n\r\n1. Add the ability to include custom C code during the compilation process by modifying Lua's Makefile (which we can now do, thanks to #59). This would be a feature added to the build script.\r\n2. Don't allow consumers of the crate to override macros, and use a combination of C and Rust to pick-and-choose how we want to handle specific macros. For example, write hardcoded implementations of `lua_lock()` and `lua_unlock()` and make thread safety a non-optional feature.\r\n3. Use function pointers and stubbing to override definitions at runtime. This would have a small runtime overhead.\r\n\r\nPersonally, (1) does not sound desirable at all, even if it can be done. I don't feel like writing _any_ C code in a Rust application that depends on lua.\r\n\r\n(2) is not desirable either, especially for the locking case. Locking incurs a notable runtime overhead that we do not want to force on users in a single-threaded application. Since this is compile-time, it might be near-impossible to be able to turn thread-safety off.\r\n\r\n(3) isn't pretty, but it kind of works and isn't as much of a runtime cost as (2) could be for some users. Calling all overridable functions would have an additional branch instruction checking for NULL before making a jump to an implementation.\r\n\r\nHere's some of the ugliness of (3) so that you can assess if it is worth it...\r\n\r\nAdding externs for values that are overridable in `lua-source/overrides.h` (we must choose what overrides we want to support):\r\n\r\n```c\r\ntypedef struct lua_State lua_State;\r\n\r\n#define lua_lock(L) \tif (LUA_LOCK_STUB != 0) { (*LUA_LOCK_STUB)(L); } else\r\n#define lua_unlock(L) \tif (LUA_UNLOCK_STUB != 0) { (*LUA_UNLOCK_STUB)(L); } else\r\n\r\nextern void (*LUA_LOCK_STUB)(lua_State* L);\r\nextern void (*LUA_UNLOCK_STUB)(lua_State* L);\r\n```\r\n\r\nDefine references for the above symbols initialized to null (`lua-source/overrides.c`):\r\n\r\n```c\r\nvoid (*LUA_LOCK_STUB)(lua_State* L) = 0;\r\nvoid (*LUA_UNLOCK_STUB)(lua_State* L) = 0;\r\n```\r\n\r\nBack to Rust, we define a macro that consumers of the crate can use to set these overridable function pointers:\r\n\r\n```rust\r\nmacro_rules! lua_override {\r\n    ($SYMBOL:ident, $f:path) => {\r\n        {\r\n            extern \"C\" {\r\n                static mut $SYMBOL: *mut $crate::libc::c_void;\r\n            }\r\n            unsafe {\r\n                $SYMBOL = {\r\n                    extern \"C\" fn fn_stub(state: *mut $crate::ffi::lua_State) {\r\n                        $f(state);\r\n                    }\r\n                    fn_stub\r\n                } as *mut $crate::libc::c_void;\r\n            }\r\n        }\r\n    };\r\n}\r\n```\r\n\r\nThis _indeed works_! A usage example:\r\n\r\n```rust\r\n#[macro_use]\r\nextern crate lua;\r\n\r\nfn main() {\r\n    lua_override!(LUA_LOCK_STUB, lock);\r\n    lua_override!(LUA_UNLOCK_STUB, unlock);\r\n\r\n    let mut state = lua::State::new();\r\n    state.do_string(\"print('hi')\");\r\n}\r\n\r\nfn lock(state: *mut lua_State) {\r\n    println!(\"lua_lock called\");\r\n}\r\n\r\nfn unlock(state: *mut lua_State) {\r\n    println!(\"lua_unlock called\");\r\n}\r\n```\r\n\r\nThis prints \"hi\" between a whole lot of \"lua_lock called\" and \"lua_unlock called\". If this approach is desirable, as it looks decent to the consumer, then I can open a PR with a tidier implementation.\r\n\r\nAre any of these good ideas? How do we want to handle macro overrides?"},"comment":{"url":"https://api.github.com/repos/jcmoyer/rust-lua53/issues/comments/244505943","html_url":"https://github.com/jcmoyer/rust-lua53/issues/67#issuecomment-244505943","issue_url":"https://api.github.com/repos/jcmoyer/rust-lua53/issues/67","id":244505943,"user":{"login":"SpaceManiac","id":222630,"avatar_url":"https://avatars.githubusercontent.com/u/222630?v=3","gravatar_id":"","url":"https://api.github.com/users/SpaceManiac","html_url":"https://github.com/SpaceManiac","followers_url":"https://api.github.com/users/SpaceManiac/followers","following_url":"https://api.github.com/users/SpaceManiac/following{/other_user}","gists_url":"https://api.github.com/users/SpaceManiac/gists{/gist_id}","starred_url":"https://api.github.com/users/SpaceManiac/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SpaceManiac/subscriptions","organizations_url":"https://api.github.com/users/SpaceManiac/orgs","repos_url":"https://api.github.com/users/SpaceManiac/repos","events_url":"https://api.github.com/users/SpaceManiac/events{/privacy}","received_events_url":"https://api.github.com/users/SpaceManiac/received_events","type":"User","site_admin":false},"created_at":"2016-09-02T22:57:24Z","updated_at":"2016-09-02T22:57:24Z","body":"Mm, seems you're right; weak symbols would be way trickier. I think your function stubbing is probably the best route, then. That macro looks a little unwieldy and can probably be simplified, but its invocation seems great. There's a variety of macros that could be overridden in `llimits.h`, but the most important ones are probably `lua_lock`, `lua_unlock`, `luai_threadyield`, and the `luai_userstateX` macros."}}
{"actor":{"display_login":"SpaceManiac"}}