1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
use std::ffi::CStr;
use std::os::raw::c_char;
use std::{mem, ptr, slice, str};
use uuid::Uuid;
/// A length-prefixed UTF-8 string.
///
/// As opposed to C strings, this string is not null-terminated. If the string is owned, indicated
/// by the `owned` flag, the owner must call the `free` function on this string. The convention is:
///
/// - When obtained as instance through return values, always free the string.
/// - When obtained as pointer through field access, never free the string.
#[repr(C)]
pub struct RelayStr {
/// Pointer to the UTF-8 encoded string data.
pub data: *mut c_char,
/// The length of the string pointed to by `data`.
pub len: usize,
/// Indicates that the string is owned and must be freed.
pub owned: bool,
}
impl RelayStr {
/// Creates a new `RelayStr` by borrowing the given `&str`.
pub(crate) fn new(s: &str) -> RelayStr {
RelayStr {
data: s.as_ptr() as *mut c_char,
len: s.len(),
owned: false,
}
}
/// Creates a new `RelayStr` by assuming ownership over the given `String`.
///
/// When dropping this `RelayStr` instance, the buffer is freed.
pub(crate) fn from_string(mut s: String) -> RelayStr {
s.shrink_to_fit();
let rv = RelayStr {
data: s.as_ptr() as *mut c_char,
len: s.len(),
owned: true,
};
mem::forget(s);
rv
}
/// Frees the string buffer if it is owned.
pub(crate) unsafe fn free(&mut self) {
if self.owned {
String::from_raw_parts(self.data as *mut _, self.len, self.len);
self.data = ptr::null_mut();
self.len = 0;
self.owned = false;
}
}
/// Returns a borrowed string.
pub(crate) unsafe fn as_str(&self) -> &str {
str::from_utf8_unchecked(slice::from_raw_parts(self.data as *const _, self.len))
}
}
// RelayStr is immutable, thus it can be Send + Sync
unsafe impl Sync for RelayStr {}
unsafe impl Send for RelayStr {}
impl Default for RelayStr {
fn default() -> RelayStr {
RelayStr {
data: ptr::null_mut(),
len: 0,
owned: false,
}
}
}
impl From<String> for RelayStr {
fn from(string: String) -> RelayStr {
RelayStr::from_string(string)
}
}
impl<'a> From<&'a str> for RelayStr {
fn from(string: &str) -> RelayStr {
RelayStr::new(string)
}
}
/// Creates a Relay string from a c string.
#[no_mangle]
#[relay_ffi::catch_unwind]
pub unsafe extern "C" fn relay_str_from_cstr(s: *const c_char) -> RelayStr {
let s = CStr::from_ptr(s).to_str()?;
RelayStr {
data: s.as_ptr() as *mut _,
len: s.len(),
owned: false,
}
}
/// Frees a Relay str.
///
/// If the string is marked as not owned then this function does not
/// do anything.
#[no_mangle]
#[relay_ffi::catch_unwind]
pub unsafe extern "C" fn relay_str_free(s: *mut RelayStr) {
if !s.is_null() {
(*s).free()
}
}
/// A 16-byte UUID.
#[repr(C)]
pub struct RelayUuid {
/// UUID bytes in network byte order (big endian).
pub data: [u8; 16],
}
impl RelayUuid {
pub(crate) fn new(uuid: Uuid) -> RelayUuid {
let data = *uuid.as_bytes();
Self { data }
}
}
impl From<Uuid> for RelayUuid {
fn from(uuid: Uuid) -> RelayUuid {
RelayUuid::new(uuid)
}
}
/// Returns true if the uuid is nil.
#[no_mangle]
#[relay_ffi::catch_unwind]
pub unsafe extern "C" fn relay_uuid_is_nil(uuid: *const RelayUuid) -> bool {
if let Ok(uuid) = Uuid::from_slice(&(*uuid).data[..]) {
uuid == Uuid::nil()
} else {
false
}
}
/// Formats the UUID into a string.
///
/// The string is newly allocated and needs to be released with
/// `relay_cstr_free`.
#[no_mangle]
#[relay_ffi::catch_unwind]
pub unsafe extern "C" fn relay_uuid_to_str(uuid: *const RelayUuid) -> RelayStr {
let uuid = Uuid::from_slice(&(*uuid).data[..]).unwrap_or_else(|_| Uuid::nil());
RelayStr::from_string(uuid.as_hyphenated().to_string())
}
/// A binary buffer of known length.
///
/// If the buffer is owned, indicated by the `owned` flag, the owner must call the `free` function
/// on this buffer. The convention is:
///
/// - When obtained as instance through return values, always free the buffer.
/// - When obtained as pointer through field access, never free the buffer.
#[repr(C)]
pub struct RelayBuf {
/// Pointer to the raw data.
pub data: *mut u8,
/// The length of the buffer pointed to by `data`.
pub len: usize,
/// Indicates that the buffer is owned and must be freed.
pub owned: bool,
}
impl RelayBuf {
pub(crate) unsafe fn free(&mut self) {
if self.owned {
Vec::from_raw_parts(self.data, self.len, self.len);
self.data = ptr::null_mut();
self.len = 0;
self.owned = false;
}
}
pub(crate) unsafe fn as_bytes(&self) -> &[u8] {
slice::from_raw_parts(self.data as *const u8, self.len)
}
}
impl Default for RelayBuf {
fn default() -> RelayBuf {
RelayBuf {
data: ptr::null_mut(),
len: 0,
owned: false,
}
}
}
/// Frees a Relay buf.
///
/// If the buffer is marked as not owned then this function does not
/// do anything.
#[no_mangle]
#[relay_ffi::catch_unwind]
pub unsafe extern "C" fn relay_buf_free(b: *mut RelayBuf) {
if !b.is_null() {
(*b).free()
}
}