diplomat_runtime/rust_interop.rs
1//! Types for interfacing with Diplomat FFI APIs from Rust.
2//!
3//! By and large, Diplomat helps you produce a Rust-written library that can be called from other
4//! languages. You write the library in Rust, but interact with the Diplomat-wrapped library
5//! in a non-Rust language.
6//!
7//! However, either for debugging purposes, or for extending the library in custom ways, you may find
8//! yourself wanting to work with the Diplomat-wrapped library from Rust. This module contains
9//! utilities for doing that.
10
11use crate::diplomat_buffer_write_create;
12use crate::diplomat_buffer_write_destroy;
13use crate::DiplomatWrite;
14use core::borrow::Borrow;
15
16/// A [`DiplomatWrite`] backed by a `Vec`, for convenient use in Rust.
17pub struct RustWriteVec {
18 /// Safety Invariant: must have been created by diplomat_buffer_write_create()
19 ptr: *mut DiplomatWrite,
20}
21
22impl RustWriteVec {
23 /// Creates a new [`RustWriteVec`] with the given initial buffer capacity.
24 pub fn with_capacity(cap: usize) -> Self {
25 Self {
26 ptr: diplomat_buffer_write_create(cap),
27 }
28 }
29
30 /// Borrows the underlying [`DiplomatWrite`].
31 #[allow(clippy::should_implement_trait)] // the trait is also implemented
32 pub fn borrow(&self) -> &DiplomatWrite {
33 // Safety: the pointer is valid because the Drop impl hasn't been called yet.
34 unsafe { &*self.ptr }
35 }
36
37 /// Mutably borrows the underlying [`DiplomatWrite`].
38 ///
39 /// # Safety
40 /// The contents of the returned pointer MUST NOT be swapped with another instance
41 /// of [`DiplomatWrite`] that may have been created from a different source. This
42 /// requirement is satisfied if this is the only instance of [`DiplomatWrite`]
43 /// in scope.
44 ///
45 /// For more information, see [`DiplomatWrite`].
46 pub unsafe fn borrow_mut(&mut self) -> &mut DiplomatWrite {
47 // Safety: the pointer is valid because the Drop impl hasn't been called yet.
48 unsafe { &mut *self.ptr }
49 }
50}
51
52impl Borrow<DiplomatWrite> for RustWriteVec {
53 fn borrow(&self) -> &DiplomatWrite {
54 self.borrow()
55 }
56}
57
58impl Drop for RustWriteVec {
59 fn drop(&mut self) {
60 // Safety: by invariant, ptr was created by diplomat_buffer_write_create()
61 unsafe { diplomat_buffer_write_destroy(self.ptr) }
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68 use core::fmt::Write;
69
70 #[test]
71 fn test_rust_write() {
72 let mut buffer = RustWriteVec::with_capacity(5);
73 // Safety: this is the only instance of `DiplomatWrite` in scope.
74 unsafe { buffer.borrow_mut() }
75 .write_str("Hello World")
76 .unwrap();
77 assert_eq!(buffer.borrow().as_bytes(), b"Hello World");
78 }
79}