diff --git a/doc/src/content/recipes/rust.md b/doc/src/content/recipes/rust.md new file mode 100644 index 00000000000..5400f3bb1c5 --- /dev/null +++ b/doc/src/content/recipes/rust.md @@ -0,0 +1,86 @@ ++++ +title = "Rust FFI" +description = "How to teach Rust about `result`." +tags = [ "Rust" ] ++++ + +A nice side effect of [Outcome.Experimental's excellent C support]({{% relref "/experimental/c-api" %}}) +is that teaching Rust about Outcome's `result` becomes trivially +easy. C and C++ results propagate _losslessly_ into Rust Results, and the +full power of the Outcome C API is available to Rust code for semantic +equivalence comparison et al. + +Here's a quick snippet to get you started. This assumes that you have declared +your C result using `CXX_DECLARE_RESULT_SYSTEM(outcome, intptr_t)` in order +to produce a C result named "outcome" compatible with an erased system code C++ result: + +```rust +// Rust representation of an Outcome.Experimental Result +pub type OutcomeCResult = Result; + +unsafe impl Send for cxx_status_code_system {} + +impl std::fmt::Display for cxx_status_code_system { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + String::from_utf8_lossy(unsafe { + CStr::from_ptr(outcome_status_code_message( + self as *const _ as *const ::std::os::raw::c_void, + )) + .to_bytes() + }) + .to_string() + ) + } +} + +impl std::fmt::Debug for cxx_status_code_system { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + String::from_utf8_lossy(unsafe { + CStr::from_ptr(outcome_status_code_message( + self as *const _ as *const ::std::os::raw::c_void, + )) + .to_bytes() + }) + .to_string() + ) + } +} + +fn to_result(res: cxx_result_status_code_system_outcome) -> OutcomeCResult { + if (res.flags & 1) == 1 { + return Ok(res.value); + } + Err(res.error) +} +``` + +Let's say there is an FFI function like this: + +```rust +unsafe extern "C" { + pub fn file_read( + arg1: *mut db, + buffer: *mut u8, + bytes: usize, + ) -> monad_c_result; +} +``` + +You can now do: + +```rust +// Make a Rust Result equivalent to the Outcome Result +let res = to_result(unsafe { file_read(db, buffer, 256) }); +// Asks Outcome for the message automatically +println!("Message: {}", res.err().unwrap()); +``` + +You can use the standard Rust `?` to TRY Rust Results, same as anywhere else in Rust. + +Easy as pie! diff --git a/include/outcome/detail/revision.hpp b/include/outcome/detail/revision.hpp index 86dbd42cd86..d210d35c0d8 100644 --- a/include/outcome/detail/revision.hpp +++ b/include/outcome/detail/revision.hpp @@ -22,6 +22,6 @@ Distributed under the Boost Software License, Version 1.0. */ // Note the second line of this file must ALWAYS be the git SHA, third line ALWAYS the git SHA update time -#define OUTCOME_PREVIOUS_COMMIT_REF d7451675c0baca0b63747fc12d3e1912e97c6e9f -#define OUTCOME_PREVIOUS_COMMIT_DATE "2024-12-12 16:28:50 +00:00" -#define OUTCOME_PREVIOUS_COMMIT_UNIQUE d7451675 +#define OUTCOME_PREVIOUS_COMMIT_REF e6c4d62c24c0591ae391bc115c287c9493bc5d00 +#define OUTCOME_PREVIOUS_COMMIT_DATE "2024-12-12 23:49:47 +00:00" +#define OUTCOME_PREVIOUS_COMMIT_UNIQUE e6c4d62c