1use std::ffi::c_void;
9use std::fmt;
10
11pub const ABI_VERSION: u32 = 1;
13
14#[repr(transparent)]
20#[derive(Copy, Clone, PartialEq, Eq, Hash)]
21pub struct NrStatus(u32);
22
23#[allow(non_upper_case_globals)]
24impl NrStatus {
25 pub const Ok: Self = Self(0);
26 pub const Err: Self = Self(1);
27 pub const Invalid: Self = Self(2);
28 pub const Unsupported: Self = Self(3);
29 pub const StreamEnd: Self = Self(4);
31 pub const Panic: Self = Self(5);
33 pub const Backpressure: Self = Self(6);
35
36 pub const fn from_raw(value: u32) -> Self {
38 Self(value)
39 }
40
41 pub const fn as_raw(self) -> u32 {
43 self.0
44 }
45
46 pub const fn is_terminal(self) -> bool {
48 matches!(
49 self,
50 Self::Err | Self::Invalid | Self::Unsupported | Self::StreamEnd | Self::Panic
51 )
52 }
53}
54
55impl fmt::Debug for NrStatus {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 let name = match *self {
58 Self::Ok => "Ok",
59 Self::Err => "Err",
60 Self::Invalid => "Invalid",
61 Self::Unsupported => "Unsupported",
62 Self::StreamEnd => "StreamEnd",
63 Self::Panic => "Panic",
64 Self::Backpressure => "Backpressure",
65 Self(value) => return f.debug_tuple("Unknown").field(&value).finish(),
66 };
67 f.write_str(name)
68 }
69}
70
71#[repr(C)]
77#[derive(Debug, Copy, Clone, Default)]
78pub struct NrStr {
79 pub ptr: *const u8,
80 pub len: u32,
81 pub _reserved: u32,
82}
83
84#[repr(C)]
87#[derive(Debug, Copy, Clone, Default)]
88pub struct NrBytes {
89 pub ptr: *const u8,
90 pub len: u64,
91}
92
93#[repr(C)]
95#[derive(Debug, Copy, Clone, Default)]
96pub struct NrKV {
97 pub key: NrStr,
98 pub value: NrStr,
99}
100
101#[derive(Debug, Clone, PartialEq, Eq)]
103pub enum NrViewError {
104 NullPointer,
106 LengthOverflow,
108 InvalidUtf8(std::str::Utf8Error),
110}
111
112impl fmt::Display for NrViewError {
113 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114 match self {
115 Self::NullPointer => f.write_str("non-empty ABI view has a null pointer"),
116 Self::LengthOverflow => f.write_str("ABI view length exceeds usize"),
117 Self::InvalidUtf8(error) => write!(f, "ABI string is not valid UTF-8: {error}"),
118 }
119 }
120}
121
122impl std::error::Error for NrViewError {
123 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
124 match self {
125 Self::InvalidUtf8(error) => Some(error),
126 Self::NullPointer | Self::LengthOverflow => None,
127 }
128 }
129}
130
131#[repr(C)]
134#[derive(Debug, Default)]
135pub struct NrKVAny {
136 key: NrStr,
137 key_storage: NrVec<u8>,
138 pub value: NrAny,
139}
140
141#[repr(C)]
144#[derive(Debug, Copy, Clone, Default)]
145pub struct NrIndexSlot {
146 pub hash: u64,
147 pub entry_idx: u32, pub state: u8, pub _pad: [u8; 3],
150}
151
152#[repr(C)]
155#[derive(Debug, Default)]
156pub struct NrMap {
157 entries: NrVec<NrKVAny>,
158 index: NrVec<NrIndexSlot>, used: u32, tomb: u32, }
162
163#[repr(C)]
166#[derive(Debug)]
167pub struct NrAny {
168 data: *mut c_void,
170 size: u64,
172 type_tag: u32,
174 clone_fn: Option<unsafe extern "C" fn(*const c_void) -> *mut c_void>,
176 drop_fn: Option<unsafe extern "C" fn(*mut c_void)>,
178}
179
180#[repr(C)]
188#[derive(Debug)]
189pub struct NrVec<T> {
190 ptr: *mut T,
191 len: usize,
192 cap: usize,
193 owned: u8,
194 _reserved: [u8; 7],
195 drop_fn: Option<unsafe extern "C" fn(*mut T, usize, usize)>,
196}
197
198impl<T> Default for NrVec<T> {
199 fn default() -> Self {
200 Self {
201 ptr: std::ptr::null_mut(),
202 len: 0,
203 cap: 0,
204 owned: 0,
205 _reserved: [0; 7],
206 drop_fn: None,
207 }
208 }
209}
210
211impl Default for NrAny {
212 fn default() -> Self {
213 Self {
214 data: std::ptr::null_mut(),
215 size: 0,
216 type_tag: 0,
217 clone_fn: None,
218 drop_fn: None,
219 }
220 }
221}
222
223#[repr(C)]
226#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
227pub struct NrTuple<A, B> {
228 pub a: A,
229 pub b: B,
230}
231
232#[repr(C)]
234#[derive(Debug, Copy, Clone)]
235pub struct NrHostVTable {
236 pub send_result: unsafe extern "C" fn(
237 host_ctx: *mut c_void,
238 sid: u64,
239 status: NrStatus,
240 payload: NrVec<u8>,
241 ) -> NrStatus,
242}
243
244#[repr(C)]
247#[derive(Debug, Copy, Clone)]
248pub struct NrHostExt {
249 pub set_state: unsafe extern "C" fn(
252 host_ctx: *mut c_void,
253 sid: u64,
254 key: NrStr,
255 value: NrBytes,
256 ) -> NrStatus,
257
258 pub get_state: unsafe extern "C" fn(host_ctx: *mut c_void, sid: u64, key: NrStr) -> NrVec<u8>,
261}
262
263unsafe impl Send for NrHostExt {}
265unsafe impl Sync for NrHostExt {}
266
267#[repr(C)]
269#[derive(Debug, Copy, Clone)]
270pub struct NrPluginVTable {
271 pub init: Option<
272 unsafe extern "C" fn(host_ctx: *mut c_void, host_vtable: *const NrHostVTable) -> NrStatus,
273 >,
274
275 pub handle: Option<unsafe extern "C" fn(entry: NrStr, sid: u64, payload: NrBytes) -> NrStatus>,
276
277 pub shutdown: Option<unsafe extern "C" fn()>,
278
279 pub stream_data: Option<unsafe extern "C" fn(sid: u64, data: NrBytes) -> NrStatus>,
280
281 pub stream_close: Option<unsafe extern "C" fn(sid: u64) -> NrStatus>,
282}
283
284#[macro_export]
285macro_rules! define_plugin {
286 (
287 init: $init_fn:path,
288 shutdown: $shutdown_fn:path,
289 entries: {
290 $($entry_name:literal => $handler_fn:path),* $(,)?
291 }
292 $(, stream_handlers: {
293 data: $stream_data_fn:path,
294 close: $stream_close_fn:path $(,)?
295 })?
296 ) => {
297 static PLUGIN_VTABLE: $crate::NrPluginVTable = $crate::NrPluginVTable {
299 init: Some(plugin_init_wrapper),
300 handle: Some(plugin_handle_wrapper),
301 shutdown: Some(plugin_shutdown_wrapper),
302 stream_data: Some(plugin_stream_data_wrapper),
303 stream_close: Some(plugin_stream_close_wrapper),
304 };
305
306 static PLUGIN_INFO: $crate::NrPluginInfo = $crate::NrPluginInfo {
308 abi_version: $crate::ABI_VERSION,
309 struct_size: std::mem::size_of::<$crate::NrPluginInfo>() as u32,
310 name: $crate::NrStr::from_static(env!("CARGO_PKG_NAME")),
311 version: $crate::NrStr::from_static(env!("CARGO_PKG_VERSION")),
312 plugin_ctx: std::ptr::null_mut(),
313 vtable: &PLUGIN_VTABLE,
314 };
315
316 #[unsafe(no_mangle)]
318 pub extern "C" fn nylon_ring_get_plugin_v1() -> *const $crate::NrPluginInfo {
319 &PLUGIN_INFO
320 }
321
322 unsafe extern "C" fn plugin_init_wrapper(
324 host_ctx: *mut std::ffi::c_void,
325 host_vtable: *const $crate::NrHostVTable,
326 ) -> $crate::NrStatus {
327 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| unsafe {
328 $init_fn(host_ctx, host_vtable)
329 }))
330 .unwrap_or($crate::NrStatus::Panic)
331 }
332
333 unsafe extern "C" fn plugin_shutdown_wrapper() {
334 let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
335 $shutdown_fn();
336 }));
337 }
338
339 unsafe extern "C" fn plugin_handle_wrapper(
340 entry: $crate::NrStr,
341 sid: u64,
342 payload: $crate::NrBytes,
343 ) -> $crate::NrStatus {
344 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
345 let entry_str = match unsafe { entry.as_str() } {
346 Ok(entry) => entry,
347 Err(_) => return $crate::NrStatus::Invalid,
348 };
349 match entry_str {
350 $(
351 $entry_name => unsafe {
352 $handler_fn(sid, payload)
353 }
354 )*
355 _ => $crate::NrStatus::Invalid,
356 }
357 }))
358 .unwrap_or($crate::NrStatus::Panic)
359 }
360
361 unsafe extern "C" fn plugin_stream_data_wrapper(
362 sid: u64,
363 data: $crate::NrBytes,
364 ) -> $crate::NrStatus {
365 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
366 let _ = (sid, data);
367 $(
368 return unsafe { $stream_data_fn(sid, data) };
369 )?
370 #[allow(unreachable_code)]
371 $crate::NrStatus::Unsupported
372 }))
373 .unwrap_or($crate::NrStatus::Panic)
374 }
375
376 unsafe extern "C" fn plugin_stream_close_wrapper(
377 sid: u64,
378 ) -> $crate::NrStatus {
379 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
380 let _ = sid;
381 $(
382 return unsafe { $stream_close_fn(sid) };
383 )?
384 #[allow(unreachable_code)]
385 $crate::NrStatus::Unsupported
386 }))
387 .unwrap_or($crate::NrStatus::Panic)
388 }
389 };
390}
391
392#[repr(C)]
394#[derive(Debug, Copy, Clone)]
395pub struct NrPluginInfo {
396 pub abi_version: u32,
397 pub struct_size: u32,
398
399 pub name: NrStr,
400 pub version: NrStr,
401
402 pub plugin_ctx: *mut c_void,
403 pub vtable: *const NrPluginVTable,
404}
405
406impl NrStr {
407 pub fn new(s: &str) -> Self {
412 let len = u32::try_from(s.len()).expect("NrStr cannot represent strings larger than 4 GiB");
413 Self {
414 ptr: s.as_ptr(),
415 len,
416 _reserved: 0,
417 }
418 }
419
420 pub const fn from_static(s: &'static str) -> Self {
422 assert!(
423 s.len() <= u32::MAX as usize,
424 "static string is too large for NrStr"
425 );
426 Self {
427 ptr: s.as_ptr(),
428 len: s.len() as u32,
429 _reserved: 0,
430 }
431 }
432
433 pub unsafe fn as_str<'a>(&self) -> Result<&'a str, NrViewError> {
441 let bytes = unsafe { view_bytes(self.ptr, u64::from(self.len))? };
442 std::str::from_utf8(bytes).map_err(NrViewError::InvalidUtf8)
443 }
444
445 pub const fn is_empty(&self) -> bool {
447 self.len == 0
448 }
449
450 pub const fn len(&self) -> usize {
452 self.len as usize
453 }
454
455 pub const fn as_ptr(&self) -> *const u8 {
457 self.ptr
458 }
459
460 pub fn clear(&mut self) {
462 self.ptr = std::ptr::null();
463 self.len = 0;
464 self._reserved = 0;
465 }
466}
467
468unsafe fn view_bytes<'a>(ptr: *const u8, len: u64) -> Result<&'a [u8], NrViewError> {
469 if len == 0 {
470 return Ok(&[]);
471 }
472 if ptr.is_null() {
473 return Err(NrViewError::NullPointer);
474 }
475 let len = usize::try_from(len).map_err(|_| NrViewError::LengthOverflow)?;
476 Ok(unsafe { std::slice::from_raw_parts(ptr, len) })
477}
478
479impl NrBytes {
480 pub fn from_slice(s: &[u8]) -> Self {
482 Self {
483 ptr: s.as_ptr(),
484 len: u64::try_from(s.len()).expect("NrBytes length does not fit in u64"),
485 }
486 }
487
488 pub unsafe fn as_slice<'a>(&self) -> Result<&'a [u8], NrViewError> {
496 unsafe { view_bytes(self.ptr, self.len) }
497 }
498
499 pub const fn is_empty(&self) -> bool {
501 self.len == 0
502 }
503
504 pub const fn len(&self) -> u64 {
506 self.len
507 }
508}
509
510impl Clone for NrKVAny {
511 fn clone(&self) -> Self {
512 Self::new(self.key(), self.value.clone())
513 }
514}
515
516impl Clone for NrMap {
517 fn clone(&self) -> Self {
518 Self {
519 entries: self.entries.clone(),
520 index: self.index.clone(),
521 used: self.used,
522 tomb: self.tomb,
523 }
524 }
525}
526
527impl Clone for NrAny {
528 fn clone(&self) -> Self {
543 if self.data.is_null() {
544 return Self::default();
545 }
546 let clone_fn = self
547 .clone_fn
548 .expect("non-null NrAny values always have a clone function");
549 let data = unsafe { clone_fn(self.data.cast_const()) };
550 assert!(!data.is_null(), "NrAny clone callback failed");
551 Self {
552 data,
553 size: self.size,
554 type_tag: self.type_tag,
555 clone_fn: self.clone_fn,
556 drop_fn: self.drop_fn,
557 }
558 }
559}
560
561impl<T: Clone> Clone for NrVec<T> {
562 fn clone(&self) -> Self {
563 if self.len == 0 {
564 return Self::default();
565 }
566 let v = self.as_slice().to_vec();
567 Self::from_vec(v)
568 }
569}
570
571impl NrKV {
572 pub fn new(key: &str, value: &str) -> Self {
573 Self {
574 key: NrStr::new(key),
575 value: NrStr::new(value),
576 }
577 }
578
579 pub fn from_nr_str(key: NrStr, value: NrStr) -> Self {
580 Self { key, value }
581 }
582}
583
584impl NrKVAny {
585 pub fn new(key: &str, value: NrAny) -> Self {
586 let key_storage = NrVec::from_vec(key.as_bytes().to_vec());
587 let key = NrStr::new(
588 std::str::from_utf8(key_storage.as_slice())
589 .expect("key bytes originate from a valid UTF-8 string"),
590 );
591 Self {
592 key,
593 key_storage,
594 value,
595 }
596 }
597
598 pub unsafe fn from_nr_str(key: NrStr, value: NrAny) -> Result<Self, NrViewError> {
604 let key = unsafe { key.as_str()? };
605 Ok(Self::new(key, value))
606 }
607
608 pub fn key(&self) -> &str {
610 unsafe { std::str::from_utf8_unchecked(self.key_storage.as_slice()) }
612 }
613}
614
615#[inline]
617fn hash_str(s: &str) -> u64 {
618 const FNV_OFFSET: u64 = 0xcbf29ce484222325;
619 const FNV_PRIME: u64 = 0x100000001b3;
620 let mut h = FNV_OFFSET;
621 for &b in s.as_bytes() {
622 h ^= b as u64;
623 h = h.wrapping_mul(FNV_PRIME);
624 }
625 h
626}
627
628impl NrMap {
629 pub fn new() -> Self {
630 Self::default()
631 }
632
633 #[inline]
634 fn index_len(&self) -> usize {
635 self.index.len
636 }
637
638 fn ensure_index(&mut self) {
639 if self.index.is_empty() && self.entries.len >= 8 {
641 self.rehash(16);
642 }
643 }
644
645 fn rehash(&mut self, mut new_cap: usize) {
646 new_cap = new_cap.next_power_of_two().max(16);
648
649 let mut slots = Vec::with_capacity(new_cap);
651 slots.resize_with(new_cap, NrIndexSlot::default);
652
653 self.index = NrVec::from_vec(slots);
654 self.used = 0;
655 self.tomb = 0;
656
657 for i in 0..self.entries.len {
659 let kv = unsafe { &*self.entries.ptr.add(i) };
660 let k = kv.key();
661 let entry_idx =
662 u32::try_from(i).expect("NrMap cannot contain more than u32::MAX entries");
663 self.index_insert(hash_str(k), entry_idx);
664 }
665 }
666
667 #[inline]
668 fn should_grow(&self) -> bool {
669 if self.index.is_empty() {
671 return false;
672 }
673 let occupied = u64::from(self.used) + u64::from(self.tomb);
674 occupied * 10 >= self.index_len() as u64 * 7
675 }
676
677 fn maybe_grow(&mut self) {
678 if self.should_grow() {
679 let cap = self.index_len();
680 self.rehash(cap * 2);
681 }
682 }
683
684 fn index_insert(&mut self, hash: u64, entry_idx: u32) {
685 let cap = self.index_len();
686 if cap == 0 {
687 return;
688 }
689 let mask = cap - 1;
690 let mut pos = (hash as usize) & mask;
691 let mut first_tomb: Option<usize> = None;
692
693 for _ in 0..cap {
694 let slot = unsafe { &mut *self.index.ptr.add(pos) };
695 match slot.state {
696 0 => {
697 let target = first_tomb.unwrap_or(pos);
698 let s2 = unsafe { &mut *self.index.ptr.add(target) };
699 s2.hash = hash;
700 s2.entry_idx = entry_idx;
701 s2.state = 1;
702 if first_tomb.is_some() {
703 self.tomb -= 1;
704 }
705 self.used += 1;
706 return;
707 }
708 2 if first_tomb.is_none() => first_tomb = Some(pos),
709 _ => {}
710 }
711 pos = (pos + 1) & mask;
712 }
713
714 let cap2 = cap * 2;
716 self.rehash(cap2);
717 self.index_insert(hash, entry_idx);
718 }
719
720 pub fn insert(&mut self, key: &str, value: NrAny) {
721 if let Some(v) = self.get_mut(key) {
723 *v = value;
724 return;
725 }
726
727 assert!(
728 self.entries.len < u32::MAX as usize,
729 "NrMap cannot contain more than u32::MAX entries"
730 );
731 let kv = NrKVAny::new(key, value);
732 self.entries.push(kv);
733
734 self.ensure_index();
735 if !self.index.is_empty() {
736 self.maybe_grow();
737 let idx = u32::try_from(self.entries.len - 1)
738 .expect("NrMap cannot contain more than u32::MAX entries");
739 self.index_insert(hash_str(key), idx);
740 }
741 }
742
743 pub unsafe fn insert_nr(&mut self, key: NrStr, value: NrAny) -> Result<(), NrViewError> {
749 let key_str = unsafe { key.as_str()? };
750 if let Some(v) = self.get_mut(key_str) {
752 *v = value;
753 return Ok(());
754 }
755
756 assert!(
757 self.entries.len < u32::MAX as usize,
758 "NrMap cannot contain more than u32::MAX entries"
759 );
760 let kv = NrKVAny::new(key_str, value);
761 self.entries.push(kv);
762
763 self.ensure_index();
764 if !self.index.is_empty() {
765 self.maybe_grow();
766 let idx = u32::try_from(self.entries.len - 1)
767 .expect("NrMap cannot contain more than u32::MAX entries");
768 self.index_insert(hash_str(key_str), idx);
769 }
770 Ok(())
771 }
772
773 pub fn get(&self, key: &str) -> Option<&NrAny> {
774 if self.index.is_empty() {
775 for kv in self.entries.iter() {
777 if kv.key() == key {
778 return Some(&kv.value);
779 }
780 }
781 return None;
782 }
783
784 let h = hash_str(key);
785 let cap = self.index.len;
786 let mask = cap - 1;
787 let mut pos = (h as usize) & mask;
788
789 for _ in 0..cap {
790 let slot = unsafe { &*self.index.ptr.add(pos) };
791 match slot.state {
792 0 => return None, 1 if slot.hash == h => {
794 let kv = unsafe { &*self.entries.ptr.add(slot.entry_idx as usize) };
795 if kv.key() == key {
796 return Some(&kv.value);
797 }
798 }
799 _ => {}
800 }
801 pos = (pos + 1) & mask;
802 }
803 None
804 }
805
806 pub fn get_mut(&mut self, key: &str) -> Option<&mut NrAny> {
807 if self.index.is_empty() {
808 for kv in self.entries.iter_mut() {
809 if kv.key() == key {
810 return Some(&mut kv.value);
811 }
812 }
813 return None;
814 }
815
816 let h = hash_str(key);
817 let cap = self.index.len;
818 let mask = cap - 1;
819 let mut pos = (h as usize) & mask;
820
821 for _ in 0..cap {
822 let slot = unsafe { &*self.index.ptr.add(pos) };
823 match slot.state {
824 0 => return None,
825 1 if slot.hash == h => {
826 let kv = unsafe { &mut *self.entries.ptr.add(slot.entry_idx as usize) };
827 if kv.key() == key {
828 return Some(&mut kv.value);
829 }
830 }
831 _ => {}
832 }
833 pos = (pos + 1) & mask;
834 }
835 None
836 }
837
838 pub fn remove(&mut self, key: &str) -> Option<NrKVAny> {
839 let (idx, removed_slot) = if self.index.is_empty() {
842 (self.entries.iter().position(|kv| kv.key() == key)?, None)
844 } else {
845 let h = hash_str(key);
847 let cap = self.index.len;
848 let mask = cap - 1;
849 let mut pos = (h as usize) & mask;
850 let mut found: Option<(usize, usize)> = None;
851
852 for _ in 0..cap {
853 let slot = unsafe { &*self.index.ptr.add(pos) };
854 match slot.state {
855 0 => break, 1 if slot.hash == h => {
857 let entry_idx = slot.entry_idx as usize;
858 let kv = unsafe { &*self.entries.ptr.add(entry_idx) };
859 if kv.key() == key {
860 found = Some((entry_idx, pos));
861 break;
862 }
863 }
864 _ => {}
865 }
866 pos = (pos + 1) & mask;
867 }
868
869 let (entry_idx, slot) = found?;
870 (entry_idx, Some(slot))
871 };
872
873 let last = self.entries.len - 1;
874
875 let removed = unsafe { std::ptr::read(self.entries.ptr.add(idx)) };
877
878 if idx != last {
879 unsafe {
881 let last_val = std::ptr::read(self.entries.ptr.add(last));
882 std::ptr::write(self.entries.ptr.add(idx), last_val);
883 }
884
885 if !self.index.is_empty() {
887 let h_last = unsafe {
888 let kv = &*self.entries.ptr.add(idx);
889 hash_str(kv.key())
890 };
891 let cap = self.index.len;
892 let mask = cap - 1;
893 let mut pos = (h_last as usize) & mask;
894
895 for _ in 0..cap {
896 let slot = unsafe { &mut *self.index.ptr.add(pos) };
897 if slot.state == 1 && slot.entry_idx == last as u32 {
898 slot.entry_idx = idx as u32;
899 break;
900 }
901 pos = (pos + 1) & mask;
902 }
903 }
904 }
905
906 self.entries.len -= 1;
907
908 if let Some(pos) = removed_slot {
910 let slot = unsafe { &mut *self.index.ptr.add(pos) };
911 debug_assert_eq!(slot.state, 1);
912 slot.state = 2;
913 self.used -= 1;
914 self.tomb += 1;
915
916 if self.should_grow() {
918 self.rehash(self.index_len().max(16));
919 }
920 }
921
922 Some(removed)
923 }
924
925 pub fn len(&self) -> usize {
926 self.entries.len
927 }
928
929 pub fn is_empty(&self) -> bool {
930 self.entries.len == 0
931 }
932
933 pub fn clear(&mut self) {
934 self.entries.clear();
935 self.index = NrVec::default();
936 self.used = 0;
937 self.tomb = 0;
938 }
939}
940
941impl NrAny {
942 pub fn new<T: Clone + Send + Sync + 'static>(value: T, type_tag: u32) -> Self {
944 let size = std::mem::size_of::<T>() as u64;
945 let data = Box::into_raw(Box::new(value)) as *mut c_void;
946 Self {
947 data,
948 size,
949 type_tag,
950 clone_fn: Some(clone_any::<T>),
951 drop_fn: Some(drop_any::<T>),
952 }
953 }
954
955 pub fn from_bytes(bytes: &[u8], type_tag: u32) -> Self {
957 Self::new(bytes.to_vec(), type_tag)
958 }
959
960 pub fn as_ptr<T>(&self) -> Result<*const T, NrStatus> {
965 if self.data.is_null() {
966 return Err(NrStatus::Invalid);
967 }
968 let expected_size = std::mem::size_of::<T>() as u64;
969 if self.size != expected_size {
970 return Err(NrStatus::Err);
971 }
972 Ok(self.data as *const T)
973 }
974
975 pub fn as_mut_ptr<T>(&mut self) -> Result<*mut T, NrStatus> {
976 if self.data.is_null() {
977 return Err(NrStatus::Invalid);
978 }
979 let expected_size = std::mem::size_of::<T>() as u64;
980 if self.size != expected_size {
981 return Err(NrStatus::Err);
982 }
983 Ok(self.data as *mut T)
984 }
985
986 pub fn is_null(&self) -> bool {
987 self.data.is_null()
988 }
989
990 pub fn type_tag(&self) -> u32 {
991 self.type_tag
992 }
993
994 pub fn size(&self) -> u64 {
995 self.size
996 }
997}
998
999unsafe extern "C" fn clone_any<T: Clone>(ptr: *const c_void) -> *mut c_void {
1000 if !ptr.is_null() {
1001 return std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1002 let value = unsafe { &*ptr.cast::<T>() };
1003 Box::into_raw(Box::new(value.clone())).cast::<c_void>()
1004 }))
1005 .unwrap_or(std::ptr::null_mut());
1006 }
1007 std::ptr::null_mut()
1008}
1009
1010unsafe extern "C" fn drop_any<T>(ptr: *mut c_void) {
1011 if !ptr.is_null() {
1012 let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| unsafe {
1013 drop(Box::from_raw(ptr.cast::<T>()));
1014 }));
1015 }
1016}
1017
1018impl Drop for NrAny {
1019 fn drop(&mut self) {
1020 if let Some(drop_fn) = self.drop_fn
1021 && !self.data.is_null()
1022 {
1023 unsafe {
1024 drop_fn(self.data);
1025 }
1026 }
1027 }
1028}
1029
1030impl NrPluginInfo {
1031 pub fn compatible(&self, expected_abi_version: u32) -> bool {
1032 self.abi_version == expected_abi_version
1033 }
1034}
1035
1036impl NrVec<u8> {
1037 pub unsafe fn from_nr_bytes(bytes: NrBytes) -> Result<Self, NrViewError> {
1043 let v = unsafe { bytes.as_slice()? }.to_vec();
1044 Ok(Self::from_vec(v))
1045 }
1046
1047 pub fn from_string(s: String) -> Self {
1048 Self::from_vec(s.into_bytes())
1049 }
1050}
1051
1052impl<T> NrVec<T> {
1053 pub fn from_vec(v: Vec<T>) -> Self {
1055 let mut v = std::mem::ManuallyDrop::new(v);
1056 let ptr = v.as_mut_ptr();
1057 let len = v.len();
1058 let cap = v.capacity();
1059 Self {
1060 ptr,
1061 len,
1062 cap,
1063 owned: 1,
1064 _reserved: [0; 7],
1065 drop_fn: Some(drop_vec::<T>),
1066 }
1067 }
1068
1069 pub fn into_vec(self) -> Vec<T>
1074 where
1075 T: Clone,
1076 {
1077 self.as_slice().to_vec()
1078 }
1079
1080 fn push(&mut self, value: T) {
1081 if self.owned == 0 && self.ptr.is_null() && self.len == 0 && self.cap == 0 {
1082 self.owned = 1;
1083 self.drop_fn = Some(drop_vec::<T>);
1084 }
1085 assert_eq!(self.owned, 1, "cannot mutate a borrowed NrVec");
1086 if self.len == self.cap {
1087 self.reserve(1);
1088 }
1089 unsafe {
1090 std::ptr::write(self.ptr.add(self.len), value);
1091 }
1092 self.len += 1;
1093 }
1094
1095 fn clear(&mut self) {
1096 assert_eq!(self.owned, 1, "cannot mutate a borrowed NrVec");
1097 while self.len > 0 {
1098 self.len -= 1;
1099 unsafe {
1100 std::ptr::drop_in_place(self.ptr.add(self.len));
1101 }
1102 }
1103 }
1104
1105 fn reserve(&mut self, additional: usize) {
1106 assert_eq!(self.owned, 1, "cannot resize a borrowed NrVec");
1107 if std::mem::size_of::<T>() == 0 {
1108 assert!(
1109 self.len.checked_add(additional).is_some(),
1110 "capacity overflow"
1111 );
1112 if self.cap == 0 {
1113 self.ptr = std::ptr::NonNull::<T>::dangling().as_ptr();
1114 self.cap = usize::MAX;
1115 }
1116 return;
1117 }
1118
1119 let available = self.cap - self.len;
1120 if available < additional {
1121 let required = self.len.checked_add(additional).expect("capacity overflow");
1122 let new_cap = if self.cap == 0 {
1123 std::cmp::max(1, required)
1124 } else {
1125 std::cmp::max(self.cap.saturating_mul(2), required)
1126 };
1127
1128 let new_layout = match std::alloc::Layout::array::<T>(new_cap) {
1129 Ok(layout) => layout,
1130 Err(_) => {
1131 std::alloc::handle_alloc_error(
1133 std::alloc::Layout::from_size_align(usize::MAX, 1)
1134 .unwrap_or_else(|_| std::alloc::Layout::new::<u8>()),
1135 )
1136 }
1137 };
1138
1139 let new_ptr = if self.cap == 0 {
1140 unsafe { std::alloc::alloc(new_layout) }
1141 } else {
1142 let old_layout = match std::alloc::Layout::array::<T>(self.cap) {
1143 Ok(layout) => layout,
1144 Err(_) => {
1145 std::alloc::handle_alloc_error(new_layout)
1148 }
1149 };
1150 unsafe { std::alloc::realloc(self.ptr as *mut u8, old_layout, new_layout.size()) }
1151 };
1152
1153 if new_ptr.is_null() {
1154 std::alloc::handle_alloc_error(new_layout);
1155 }
1156
1157 self.ptr = new_ptr as *mut T;
1158 self.cap = new_cap;
1159 }
1160 }
1161
1162 pub fn capacity(&self) -> usize {
1163 self.cap
1164 }
1165
1166 pub fn len(&self) -> usize {
1167 self.len
1168 }
1169
1170 pub fn is_empty(&self) -> bool {
1171 self.len == 0
1172 }
1173
1174 pub fn as_ptr(&self) -> *const T {
1175 self.ptr
1176 }
1177
1178 pub fn as_mut_ptr(&mut self) -> *mut T {
1179 self.ptr
1180 }
1181}
1182
1183impl<T> Drop for NrVec<T> {
1184 fn drop(&mut self) {
1185 if self.owned == 1
1186 && let Some(drop_fn) = self.drop_fn
1187 {
1188 unsafe {
1189 drop_fn(self.ptr, self.len, self.cap);
1190 }
1191 }
1192 }
1193}
1194
1195unsafe extern "C" fn drop_vec<T>(ptr: *mut T, len: usize, cap: usize) {
1196 let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1197 if cap != 0 {
1198 unsafe {
1199 drop(Vec::from_raw_parts(ptr, len, cap));
1200 }
1201 }
1202 }));
1203}
1204
1205impl<T> NrVec<T> {
1206 pub fn iter(&self) -> std::slice::Iter<'_, T> {
1207 self.as_slice().iter()
1208 }
1209
1210 fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
1211 self.as_mut_slice().iter_mut()
1212 }
1213
1214 pub fn as_slice(&self) -> &[T] {
1215 if self.len == 0 {
1216 &[]
1217 } else {
1218 unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
1219 }
1220 }
1221
1222 fn as_mut_slice(&mut self) -> &mut [T] {
1223 if self.len == 0 {
1224 &mut []
1225 } else {
1226 unsafe { std::slice::from_raw_parts_mut(self.ptr, self.len) }
1227 }
1228 }
1229}
1230
1231impl<'a, T> IntoIterator for &'a NrVec<T> {
1232 type Item = &'a T;
1233 type IntoIter = std::slice::Iter<'a, T>;
1234
1235 fn into_iter(self) -> Self::IntoIter {
1236 self.iter()
1237 }
1238}
1239
1240impl<T: Clone> IntoIterator for NrVec<T> {
1241 type Item = T;
1242 type IntoIter = std::vec::IntoIter<T>;
1243
1244 fn into_iter(self) -> Self::IntoIter {
1245 self.into_vec().into_iter()
1246 }
1247}
1248
1249unsafe impl Send for NrStr {}
1252unsafe impl Sync for NrStr {}
1253
1254unsafe impl Send for NrBytes {}
1255unsafe impl Sync for NrBytes {}
1256
1257unsafe impl Send for NrKV {}
1258unsafe impl Sync for NrKV {}
1259
1260unsafe impl Send for NrKVAny {}
1261unsafe impl Sync for NrKVAny {}
1262
1263unsafe impl Send for NrMap {}
1264unsafe impl Sync for NrMap {}
1265
1266unsafe impl Send for NrAny {}
1267unsafe impl Sync for NrAny {}
1268
1269unsafe impl Send for NrHostVTable {}
1270unsafe impl Sync for NrHostVTable {}
1271
1272unsafe impl Send for NrPluginVTable {}
1273unsafe impl Sync for NrPluginVTable {}
1274
1275unsafe impl Send for NrPluginInfo {}
1276unsafe impl Sync for NrPluginInfo {}
1277
1278unsafe impl<T: Send> Send for NrVec<T> {}
1279unsafe impl<T: Sync> Sync for NrVec<T> {}
1280
1281unsafe impl<A: Send, B: Send> Send for NrTuple<A, B> {}
1282unsafe impl<A: Sync, B: Sync> Sync for NrTuple<A, B> {}
1283
1284#[cfg(test)]
1285mod tests {
1286 use super::*;
1287 use std::mem::{align_of, size_of};
1288
1289 unsafe fn test_plugin_init(_: *mut c_void, _: *const NrHostVTable) -> NrStatus {
1290 NrStatus::Ok
1291 }
1292
1293 unsafe fn panicking_handler(_: u64, _: NrBytes) -> NrStatus {
1294 panic!("test panic must not cross the FFI boundary");
1295 }
1296
1297 fn test_plugin_shutdown() {}
1298
1299 define_plugin! {
1300 init: test_plugin_init,
1301 shutdown: test_plugin_shutdown,
1302 entries: {
1303 "panic" => panicking_handler,
1304 }
1305 }
1306
1307 #[test]
1308 fn test_layout() {
1309 assert_eq!(size_of::<NrStr>(), 16);
1312 assert_eq!(align_of::<NrStr>(), 8);
1313
1314 assert_eq!(size_of::<NrBytes>(), 16);
1317 assert_eq!(align_of::<NrBytes>(), 8);
1318
1319 assert_eq!(size_of::<NrVec<u8>>(), 40);
1321 assert_eq!(align_of::<NrVec<u8>>(), 8);
1322
1323 assert_eq!(size_of::<NrTuple<u64, u64>>(), 16);
1326 assert_eq!(align_of::<NrTuple<u64, u64>>(), 8);
1327
1328 assert_eq!(size_of::<NrKV>(), 32);
1331 assert_eq!(align_of::<NrKV>(), 8);
1332 }
1333
1334 #[test]
1335 fn test_nr_vec() {
1336 let mut v = NrVec::<u32>::default();
1337 assert_eq!(v.len, 0);
1338 assert_eq!(v.cap, 0);
1339
1340 v.push(1);
1341 assert_eq!(v.len, 1);
1342 assert!(v.cap >= 1);
1343 unsafe {
1344 assert_eq!(*v.ptr, 1);
1345 }
1346
1347 v.push(2);
1348 assert_eq!(v.len, 2);
1349 unsafe {
1350 assert_eq!(*v.ptr.add(1), 2);
1351 }
1352
1353 v.reserve(10);
1354 assert!(v.cap >= 12); v.clear();
1357 assert_eq!(v.len, 0);
1358 assert!(v.cap >= 12);
1359 }
1360 #[test]
1361 fn test_nr_vec_iter() {
1362 let mut v = NrVec::<u32>::default();
1363 v.push(1);
1364 v.push(2);
1365 v.push(3);
1366
1367 let mut iter = v.iter();
1368 assert_eq!(iter.next(), Some(&1));
1369 assert_eq!(iter.next(), Some(&2));
1370 assert_eq!(iter.next(), Some(&3));
1371 assert_eq!(iter.next(), None);
1372 }
1373
1374 #[test]
1375 fn test_nr_vec_iter_mut() {
1376 let mut v = NrVec::<u32>::default();
1377 v.push(1);
1378 v.push(2);
1379 v.push(3);
1380
1381 for x in v.iter_mut() {
1382 *x *= 2;
1383 }
1384
1385 let mut iter = v.iter();
1386 assert_eq!(iter.next(), Some(&2));
1387 assert_eq!(iter.next(), Some(&4));
1388 assert_eq!(iter.next(), Some(&6));
1389 assert_eq!(iter.next(), None);
1390 }
1391
1392 #[test]
1393 fn test_nr_vec_into_iter() {
1394 let mut v = NrVec::<u32>::default();
1395 v.push(1);
1396 v.push(2);
1397 v.push(3);
1398
1399 let mut iter = v.into_iter();
1400 assert_eq!(iter.next(), Some(1));
1401 assert_eq!(iter.next(), Some(2));
1402 assert_eq!(iter.next(), Some(3));
1403 assert_eq!(iter.next(), None);
1404 }
1405
1406 #[test]
1407 fn test_nr_vec_empty_and_zero_sized_values() {
1408 assert!(NrVec::<u8>::default().into_vec().is_empty());
1409
1410 let mut values = NrVec::default();
1411 values.push(());
1412 values.push(());
1413 assert_eq!(values.len(), 2);
1414 assert_eq!(values.into_iter().count(), 2);
1415 }
1416
1417 #[test]
1418 fn test_nr_vec_collect() {
1419 let mut v = NrVec::<u32>::default();
1420 v.push(10);
1421 v.push(20);
1422
1423 let collected: Vec<u32> = v.iter().cloned().collect();
1424 assert_eq!(collected, vec![10, 20]);
1425 }
1426
1427 #[test]
1428 fn test_nr_map() {
1429 let mut map = NrMap::new();
1430 assert!(map.is_empty());
1431 assert_eq!(map.len(), 0);
1432
1433 let str_value1 = NrAny::new(String::from("value1"), 1);
1435 let str_value2 = NrAny::new(String::from("value2"), 1);
1436 map.insert("key1", str_value1);
1437 map.insert("key2", str_value2);
1438 assert_eq!(map.len(), 2);
1439
1440 let value1 = map.get("key1").unwrap();
1442 let str_ptr1 = value1.as_ptr::<String>().unwrap();
1443 unsafe {
1444 assert_eq!(*str_ptr1, "value1");
1445 }
1446
1447 let value2 = map.get("key2").unwrap();
1448 let str_ptr2 = value2.as_ptr::<String>().unwrap();
1449 unsafe {
1450 assert_eq!(*str_ptr2, "value2");
1451 }
1452
1453 assert!(map.get("key3").is_none());
1454
1455 let value_mut = map.get_mut("key1");
1457 assert!(value_mut.is_some());
1458
1459 let int_value = NrAny::new(42i32, 2);
1461 map.insert("key3", int_value);
1462 assert_eq!(map.len(), 3);
1463
1464 let int_val = map.get("key3").unwrap();
1465 let int_ptr = int_val.as_ptr::<i32>().unwrap();
1466 unsafe {
1467 assert_eq!(*int_ptr, 42);
1468 }
1469
1470 let removed = map.remove("key2");
1471 assert!(removed.is_some());
1472 assert_eq!(map.len(), 2);
1473 assert!(map.get("key2").is_none());
1474
1475 map.clear();
1476 assert!(map.is_empty());
1477
1478 {
1480 let temporary_key = String::from("owned-key");
1481 map.insert(&temporary_key, NrAny::new(7_u32, 2));
1482 }
1483 let stored = map.get("owned-key").unwrap();
1484 assert_eq!(unsafe { *stored.as_ptr::<u32>().unwrap() }, 7);
1485
1486 for index in 0..16 {
1488 map.insert(&format!("key-{index}"), NrAny::new(index, 2));
1489 }
1490 for index in 0..16 {
1491 assert!(map.remove(&format!("key-{index}")).is_some());
1492 }
1493 map.clear();
1494 assert!(map.get("missing").is_none());
1495 }
1496
1497 #[test]
1498 fn test_nr_any() {
1499 let any_int = NrAny::new(42i32, 1);
1500 assert!(!any_int.is_null());
1501 assert_eq!(any_int.type_tag(), 1);
1502 assert_eq!(any_int.size(), std::mem::size_of::<i32>() as u64);
1503
1504 let ptr = any_int.as_ptr::<i32>().unwrap();
1505 unsafe {
1506 assert_eq!(*ptr, 42);
1507 }
1508
1509 let any_string = NrAny::new(String::from("hello"), 2);
1510 assert_eq!(any_string.type_tag(), 2);
1511 let str_ptr = any_string.as_ptr::<String>().unwrap();
1512 unsafe {
1513 assert_eq!(*str_ptr, "hello");
1514 }
1515 let cloned_string = any_string.clone();
1516 let cloned_ptr = cloned_string.as_ptr::<String>().unwrap();
1517 unsafe {
1518 assert_eq!(*cloned_ptr, "hello");
1519 assert_ne!(str_ptr, cloned_ptr);
1520 }
1521
1522 let any_bytes = NrAny::from_bytes(b"test", 3);
1523 assert_eq!(any_bytes.type_tag(), 3);
1524 assert_eq!(any_bytes.size(), std::mem::size_of::<Vec<u8>>() as u64);
1525 let bytes_ptr = any_bytes.as_ptr::<Vec<u8>>().unwrap();
1526 unsafe {
1527 assert_eq!(&*bytes_ptr, b"test");
1528 }
1529
1530 let default_any = NrAny::default();
1531 assert!(default_any.is_null());
1532 assert_eq!(default_any.type_tag(), 0);
1533 assert_eq!(default_any.size(), 0);
1534
1535 assert_eq!(default_any.as_ptr::<i32>(), Err(NrStatus::Invalid));
1537 let mut default_any_mut = NrAny::default();
1538 assert_eq!(default_any_mut.as_mut_ptr::<i32>(), Err(NrStatus::Invalid));
1539
1540 let any_int = NrAny::new(42i32, 1);
1542 assert_eq!(any_int.as_ptr::<u64>(), Err(NrStatus::Err)); let mut any_int_mut = NrAny::new(42i32, 1);
1544 assert_eq!(any_int_mut.as_mut_ptr::<u64>(), Err(NrStatus::Err));
1545 }
1546
1547 #[test]
1548 fn test_borrowed_view_validation() {
1549 let empty = NrStr::default();
1550 assert_eq!(unsafe { empty.as_str() }.unwrap(), "");
1551
1552 let invalid_utf8 = [0xff];
1553 let invalid = NrStr {
1554 ptr: invalid_utf8.as_ptr(),
1555 len: 1,
1556 _reserved: 0,
1557 };
1558 assert!(matches!(
1559 unsafe { invalid.as_str() },
1560 Err(NrViewError::InvalidUtf8(_))
1561 ));
1562
1563 let null_bytes = NrBytes {
1564 ptr: std::ptr::null(),
1565 len: 1,
1566 };
1567 assert_eq!(
1568 unsafe { null_bytes.as_slice() },
1569 Err(NrViewError::NullPointer)
1570 );
1571 }
1572
1573 #[test]
1574 fn plugin_macro_contains_panics_and_rejects_invalid_utf8() {
1575 let panic_entry = NrStr::new("panic");
1576 assert_eq!(
1577 unsafe { plugin_handle_wrapper(panic_entry, 1, NrBytes::default()) },
1578 NrStatus::Panic
1579 );
1580
1581 let invalid_utf8 = [0xff];
1582 let invalid_entry = NrStr {
1583 ptr: invalid_utf8.as_ptr(),
1584 len: 1,
1585 _reserved: 0,
1586 };
1587 assert_eq!(
1588 unsafe { plugin_handle_wrapper(invalid_entry, 2, NrBytes::default()) },
1589 NrStatus::Invalid
1590 );
1591 }
1592}