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}