Returning strings: Write
Most languages have their own type to handle strings. To avoid unnecessary allocations, Diplomat supports DiplomatWrite, a type with a Write implementation which can be used to write to appropriate string types on the other side.
For example, if we want to have methods that philosophically return a String or a Result<String>, we can do the following:
#![allow(unused)]
fn main() {
#[diplomat::bridge]
mod ffi {
use diplomat_runtime::DiplomatWrite;
use std::fmt::Write;
#[diplomat::opaque]
#[derive(Debug)]
pub struct Thingy(u8);
impl Thingy {
pub fn debug_output(&self, write: &mut DiplomatWrite) {
write!(write, "{:?}", self);
}
pub fn maybe_get_string(&self, write: &mut DiplomatWrite) -> Result<(), ()> {
write!(write, "integer is {}", self.0).map_err(|_| ())
}
}
}
}
On the JS side these will get converted to APIs that return strings (maybe_get_string will potentially throw in the case of an error, as is usual with DiplomatResult)
In C++ these become APIs that return std::string and diplomat::result<std::string, std::monostate> respectively.
Essentially, versions of the API returning std::string are generated, where the write!() operation will end up writing directly to the std::string with no additional intermediate Rust String allocations.