-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Guide Rewrite #64
Comments
I think a good example would be using the system |
@derekdreery that's a really good idea! I wrote an example that wraps |
@Michael-F-Bryan I wrote a really long response that github/my browser conspired to delete :(. I think your example is fine. I'd add that the call to EDIT Oh, and also implementing |
Thanks for spotting the bug @derekdreery, I had another look at the code and fixed the issue. I believe it steps from the fact that I was creating a |
I remember coming across the reddit post, but I just recently needed this rewrite of your guide. The rewrite is a little less Qt focused. I am trying to embed the Jim Tcl interpreter, so I am wrapping a long-lived C pointer that is managing it's own world under the hood. That's all to say, this work has been helpful for me! |
Thanks @anxiousmodernman! I'm actually planning to add a worked example of embedding an interpreter in Rust, so your experience may be useful. Is there anything you think others would benefit from knowing when trying to embed one language within another? Normally I'd reach for Lua here, but it feels a bit like cheating since I've already done lots with embedding Lua in Rust and because the language is actually designed for that purpose. |
My first attempt was straightforward: to write a .so library in Rust that will be auto-loaded by the scripting language. This lets us write language extensions in Rust that present themselves as "importable" libraries in Jim Tcl. This works, but it assumes the user has the interpreter installed at the system level. My next attempt is in the design phase right now: how can we 1) link all the interpreter code into our rust binary and 2) generically specify, in Rust, the structure of a language extension, so that folks can merely implement a trait, and load those extensions/DSLs in to the interpreter at runtime. Something like: let interp = Interpreter::new();
let my_dsl = MyDSL::new();
interp.load_ext(my_dsl)?;
let val = interp.eval("some custom language")?; Jim has a complicated Generically specifying the structure of a command will be an interesting challenge. I will post here if I figure it out in my next version. |
Could you also thematize |
@i-schuetz can you give me an example? Shouldn't you be using something like You shouldn't be passing a Rust object with a destructor by value across the FFI boundary because it'll most likely be Another more satisfying approach is to use |
@Michael-F-Bryan Thanks for the quick reply! Example: use std::os::raw::{c_char};
use core_foundation::string::{CFString, CFStringRef};
use core_foundation::base::TCFType;
// ...
#[no_mangle]
pub unsafe extern "C" fn get_reports(interval_number: u32, interval_length: u32) -> CFStringRef {
let result = COMP_ROOT.api.get_reports(interval_number as u64, interval_length as u64);
let lib_result = match result {
Ok(success) => LibResult { status: 200, data: Some(success), error_message: None },
Err(e) => LibResult { status: e.http_status, data: None, error_message: Some(e.to_string()) }
};
let lib_result_string = serde_json::to_string(&lib_result).unwrap();
let cf_string = CFString::new(&lib_result_string);
let cf_string_ref = cf_string.as_concrete_TypeRef();
::std::mem::forget(cf_string);
return cf_string_ref;
} (I'm not 100% sure it works correctly, adopted it from other code. If it's incorrect I'd appreciate clarification / what to use instead) Note that this is to communicate with an iOS app, thus the core_foundation dependencies. |
That Ideally, Also... Try to avoid using If you're lucky the unwinding code will detect that it's leaving a Rust stack frame and abort (or not), otherwise there's a good chance you'll have a corrupted stack or other fun issues, although it tends to be less UB on Windows because panicking is kinda handled by the OS. |
Thanks @Michael-F-Bryan! Yeah, I don't know why And yeah, I have to remove those Have you thought about adding a section for mobile (iOS / Android, essentially essentially Core Foundation and JNI) apps to this guide? Rust is a really good fit for cross-platform domain logic / services in mobile apps and a nice alternative to Kotlin Native (and partly to React Native, Flutter, etc.), in particular because of its low footprint, performance and that it can be reused for Web too via WebAssembly or even Desktop apps. Having a dedicated guide would be very helpful and possibly popularize this approach. |
It's been a while since I last updated the guide and I've learned a lot since then. I think it may be a good idea to start over and take a slightly different approach.
I think we may want to break things into two parts. In the first part we'll address common patterns and techniques used when writing FFI code, with the second part being a worked example (or two?) that lets us show off these techniques.
Progress so far (rendered)
Concepts and Patterns:
#[no_mangle]
,extern fn ...
and all that) (Created a "basics" chapter #66)&[u8]
,char*
, etc) (Arrays Chapter #69)free
and what happens if you free from the wrong allocator)dlopen
/LoadLibrary
) (Plugins and dynamic loading #71)cmake
)Ideas for worked examples:
reqwest
to do HTTP requests in the background)The text was updated successfully, but these errors were encountered: