#[repr(C)]pub struct DiplomatWrite {
context: *mut c_void,
buf: *mut u8,
len: usize,
cap: usize,
grow_failed: bool,
flush: extern "C" fn(*mut DiplomatWrite),
grow: extern "C" fn(*mut DiplomatWrite, usize) -> bool,
}Expand description
An object that can one can write UTF-8 strings to
This allows the C API to write to arbitrary kinds of objects, for example a C++ std::string or a char buffer.
The way to use this object is to fill out the buf, len, cap fields with
appropriate values for the buffer, its current length, and its current capacity,
and flush and grow with appropriate callbacks (using context to reference any
state they need). This object will be passed by mutable reference to the Rust side,
and Rust will write to it, calling grow() as necessary. Once done, it will call flush()
to update any state on context (e.g. adding a null terminator, updating the length).
The object on the foreign side will be directly usable after this, the foreign side
need not perform additional state updates after passing an DiplomatWrite to
a function.
May be extended in the future to support further invariants
DiplomatWrite will not perform any cleanup on context or buf, these are logically
“borrows” from the FFI side.
§DiplomatWrite is Polymorphic
Instances of DiplomatWrite can be created from multiple different sources.
There are two constructors available in diplomat_runtime:
diplomat_simple_write()to write to a fixed-size buffer.diplomat_buffer_write_create()to write to a Vec allocated by Rust. A wrapper is provided:RustWriteVec.
Backends may have additional constructors for writing to various shapes of buffer.
⚠️ Because DiplomatWrite is polymorphic, the destructor must know how the instance
was constructed. It is therefore unsound to use functions such as core::mem::swap
on instances of DiplomatWrite with potentially different sources. For example,
the following code is not safe:
use diplomat_runtime::DiplomatWrite;
fn bad(write: &mut DiplomatWrite) {
let mut some_other_write: DiplomatWrite = unimplemented!();
// Not safe! The two `DiplomatWrite`s have different invariants
core::mem::swap(write, &mut some_other_write);
}As a result, any function that returns an owned DiplomatWrite or a &mut DiplomatWrite
must be unsafe. For an example, see [RustWriteVec::borrow_mut].
Diplomat backends guarantee they will only ever hand the same type of DiplomatWrite object to Rust
code; this is only something you need to worry about if using RustWriteVec,
or DiplomatWrite objects manually created in Rust via APIs like diplomat_simple_write.
§Safety invariants:
flush()andgrow()will be passedselfincludingcontextand it should always be safe to do so.contextmay be null, howeverflush()andgrow()must then be ready to receive it as such.bufmust be a valid pointer tocapbytes of memorybufmust point tolenconsecutive properly initialized bytescapmust be less than or equal to isize::MAXgrow()must either return false or updatebufandcapfor a valid buffer of at least the requested buffer size.- If grow_failed is true all safety invariants on buf/cap/len MUST still hold.
DiplomatWrite::flush()will be automatically called by Diplomat.flush()might also be called (erroneously) on the Rust side (it’s a public method), so it must be idempotent.
Fields§
§context: *mut c_voidContext pointer for additional data needed by grow() and flush(). May be null.
The pointer may reference structured data on the foreign side, such as C++ std::string, used to reallocate buf.
buf: *mut u8The raw string buffer, which will be mutated on the Rust side.
len: usizeThe current filled size of the buffer
cap: usizeThe current capacity of the buffer
grow_failed: boolSet to true if grow ever fails.
flush: extern "C" fn(*mut DiplomatWrite)Called by Rust to indicate that there is no more data to write.
May be called multiple times.
Arguments:
self(*mut DiplomatWrite): ThisDiplomatWrite
grow: extern "C" fn(*mut DiplomatWrite, usize) -> boolCalled by Rust to request more capacity in the buffer. The implementation should allocate a new
buffer and copy the contents of the old buffer into the new buffer, updating self.buf and self.cap
Arguments:
self(*mut DiplomatWrite): ThisDiplomatWritecapacity(usize): The requested capacity.
Returns: true if the allocation succeeded. Should not update any state if it failed.