easy_ffi_wrapper/
lib.rs

1#![doc = include_str!("../README.md")]
2#![deny(warnings, missing_debug_implementations, missing_docs)]
3
4use std::fmt;
5
6/// Constructs a slice from raw parts (same as [`slice::from_raw_parts`]),
7/// but safely handle `{ptr: nullptr, len:0}`, which is often allowed in FFI.
8///
9/// # Safety
10///
11/// Same as [`slice::from_raw_parts`].
12///
13/// [`slice::from_raw_parts`]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html
14///
15/// Example
16/// ```
17/// mod bindings {
18///     pub enum Data {}
19///
20///     extern {
21///         pub fn get_my_data_from_c(object: *const Data, start: *mut *const u32, size: *mut usize);
22///     }
23/// }
24/// use bindings::Data as Data;
25/// impl Data {
26///     pub fn my_data(&self) -> &[u32] {
27///         unsafe {
28///             let (mut ptr, mut len) = (std::ptr::null(), 0);
29///             bindings::get_my_data_from_c(self, &mut ptr, &mut len);
30///             easy_ffi_wrapper::slice_from_raw_parts(ptr, len)
31///         }
32///     }
33/// }
34/// ```
35pub unsafe fn slice_from_raw_parts<'a, T>(ptr: *const T, len: usize) -> &'a [T] {
36    if !ptr.is_null() {
37        std::slice::from_raw_parts(ptr, len)
38    } else {
39        std::slice::from_raw_parts(std::ptr::NonNull::dangling().as_ref(), 0)
40    }
41}
42
43/// Wraps a non-owned FFI string without the overhead of CString/String
44///
45/// This allows the user of the API to choose if they want to treat the string
46/// as a bunch of bytes ([`bytes`]), verify it as a utf8 `str` ([`as_str`]), or
47/// convert it lossily into a `Cow<str>` ([`to_str_lossy`]).
48///
49/// # Example
50///
51/// ```
52/// mod bindings {
53/// #   use std::os::raw::c_char;
54///     pub enum Data {}
55///
56///     extern {
57///         pub fn get_my_data_from_c(object: *const Data, start: *mut *const c_char, size: *mut usize);
58///     }
59/// }
60/// use bindings::Data as Data;
61/// impl Data {
62///     pub fn my_data(&self) -> easy_ffi_wrapper::Str {
63///         let mut value = easy_ffi_wrapper::StrBuilder::new();
64///         unsafe {
65///             bindings::get_my_data_from_c(self, &mut value.ptr, &mut value.len);
66///             value.build()
67///         }
68///     }
69/// }
70/// ```
71#[derive(Clone, Copy)]
72pub struct Str<'a> {
73    data: &'a [u8],
74}
75
76impl<'a> Str<'a> {
77    /// Construct a string from `ptr` + `len`.
78    ///
79    /// No terminating `\0` required, and invalid UTF8 possible.
80    ///
81    /// # Safety
82    ///
83    /// Cf. [`slice_from_raw_parts`].
84    ///
85    /// [`slice_from_raw_parts`]: fn.slice_from_raw_parts.html
86    pub unsafe fn from_raw_parts(ptr: *const std::os::raw::c_char, len: usize) -> Self {
87        Self {
88            data: slice_from_raw_parts(ptr as *const u8, len),
89        }
90    }
91
92    /// Get access to raw bytes
93    pub fn bytes(&self) -> &'a [u8] {
94        self.data
95    }
96
97    /// Try converting from UTF8
98    pub fn to_str(&self) -> Result<&'a str, std::str::Utf8Error> {
99        std::str::from_utf8(self.data)
100    }
101
102    /// Try converting from UTF8 and replace invalid characters
103    pub fn to_str_lossy(&self) -> std::borrow::Cow<'a, str> {
104        String::from_utf8_lossy(self.data)
105    }
106}
107
108impl fmt::Debug for Str<'_> {
109    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
110        write!(f, "{}", self.to_str_lossy())
111    }
112}
113
114impl<'a> std::ops::Deref for Str<'a> {
115    type Target = &'a [u8];
116
117    fn deref(&self) -> &Self::Target {
118        &self.data
119    }
120}
121
122impl AsRef<[u8]> for Str<'_> {
123    fn as_ref(&self) -> &[u8] {
124        self.data
125    }
126}
127
128/// A convenience structure for calling FFI interfaces to get strings
129///
130/// # Example
131///
132/// ```
133/// mod bindings {
134/// #   use std::os::raw::c_char;
135///     pub enum Data {}
136///
137///     extern {
138///         pub fn get_my_data_from_c(object: *const Data, start: *mut *const c_char, size: *mut usize);
139///     }
140/// }
141/// use bindings::Data as Data;
142/// impl Data {
143///     pub fn my_data(&self) -> easy_ffi_wrapper::Str {
144///         let mut value = easy_ffi_wrapper::StrBuilder::new();
145///         unsafe {
146///             bindings::get_my_data_from_c(self, &mut value.ptr, &mut value.len);
147///             value.build()
148///         }
149///     }
150/// }
151/// ```
152#[derive(Debug)]
153pub struct StrBuilder {
154    /// Pointer to the first character of the string to fill in, usually as an output parameter.
155    pub ptr: *const std::os::raw::c_char,
156    /// Len of the string to fill in, usually as an output parameter.
157    pub len: usize,
158}
159
160impl StrBuilder {
161    /// Creates a new builder referencing an empty string.
162    pub fn new() -> Self {
163        StrBuilder {
164            ptr: std::ptr::null(),
165            len: 0,
166        }
167    }
168
169    /// Construct a string from `ptr` + `len`.
170    ///
171    /// No terminating `\0` required, and invalid UTF8 possible.
172    ///
173    /// # Safety
174    ///
175    /// Same as [`slice_from_raw_parts`] with `self.ptr` and `self.len` as
176    /// parameters.
177    ///
178    /// [`slice_from_raw_parts`]: fn.slice_from_raw_parts.html
179    pub unsafe fn build<'a, 'b>(&'a self) -> Str<'b> {
180        Str::from_raw_parts(self.ptr, self.len)
181    }
182}
183
184impl Default for StrBuilder {
185    fn default() -> Self {
186        Self::new()
187    }
188}
189
190/// Generates an owned type `BoxedTypeName` for a FFI type `TypeName`.
191///
192/// The generated type `BoxedTypeName` behaves like `Box<TypeName>` with a custom destructor.
193/// Box types implement: `Drop`, `Deref`, `DerefMut`, `AsRef`, `Borrow`, `Clone`, `Default`.
194///
195/// ## Example
196///
197/// ```no_run
198/// # #[macro_use] extern crate easy_ffi_wrapper;
199/// mod bindings {
200///     pub enum TypeName {}
201///
202///     extern {
203///         pub fn type_name_create() -> *mut TypeName;
204///         pub fn type_name_release(object: *mut TypeName);
205///         pub fn type_name_clone(object: *const TypeName) -> *mut TypeName;
206///     }
207/// }
208/// use bindings::TypeName as TypeName;
209/// easy_ffi_wrapper::ffi_box!(
210///     TypeName,
211///     BoxedTypeName,
212///     debug, // optional; omit if debug output is not supported
213///     delete(bindings::type_name_release),
214///     new(bindings::type_name_create),  // optional default constructor
215///     clone(bindings::type_name_clone)  // optional copy constructor
216/// );
217/// ```
218///
219/// ## Rationale behind
220///
221/// If Rust's built-in box type `Box<T>` had a facility to provide a custom destructor, we would not
222/// need to generate such box types, since we could just use the built-in type.
223#[macro_export]
224macro_rules! ffi_box {
225    (@impl, $type:ident, $boxed_type:ident, new($func:path)) => {
226        impl $type {
227            #[allow(clippy::new_ret_no_self)]
228            pub fn new() -> $boxed_type {
229                unsafe { $boxed_type { ptr: std::ptr::NonNull::new($func()).unwrap() } }
230            }
231        }
232
233        impl Default for $boxed_type {
234            fn default() -> $boxed_type {
235                $type::new()
236            }
237        }
238    };
239
240    (@impl, $type:ident, $boxed_type:ident, clone($func:path)) => {
241        impl Clone for $boxed_type {
242            fn clone(&self) -> $boxed_type {
243                self.as_ref( ).to_owned( )
244            }
245        }
246
247        impl std::borrow::ToOwned for $type {
248            type Owned = $boxed_type;
249
250            fn to_owned(&self) -> Self::Owned {
251                unsafe{ $boxed_type::from_raw($func(self)) }
252            }
253        }
254    };
255
256    ($type:ident, $boxed_type:ident, debug, delete($delete_func:path) $(, $func_type:ident($func:path))*) => {
257        ffi_box!($type, $boxed_type, delete($delete_func) $(, $func_type($func))*);
258
259        impl std::fmt::Debug for $boxed_type {
260            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
261                self.ptr.fmt(f)
262             }
263        }
264    };
265
266    ($type:ident, $boxed_type:ident, delete($delete_func:path) $(, $func_type:ident($func:path))*) => {
267        pub struct $boxed_type {
268            ptr: std::ptr::NonNull<$type>,
269        }
270
271        impl $boxed_type {
272            /// Take ownership of a raw pointer. Must not be null.
273            ///
274            /// # Safety
275            ///
276            /// This function is unsafe as there is no guarantee that the given pointer is valid,
277            /// nor whether the lifetime inferred is a suitable lifetime for the returned object.
278            pub unsafe fn from_raw( ptr: *mut $type ) -> Self {
279                Self{ ptr: std::ptr::NonNull::new(ptr).unwrap() }
280            }
281
282            /// Take ownership of a raw pointer. In case of null returns None.
283            ///
284            /// # Safety
285            ///
286            /// This function is unsafe as there is no guarantee whether the lifetime inferred is a
287            /// suitable lifetime for the returned object.
288            pub unsafe fn from_raw_checked( ptr: *mut $type ) -> Option<Self> {
289                std::ptr::NonNull::new(ptr).map(|ptr| Self{ptr})
290            }
291
292            /// Releases ownership if the raw pointer without calling the deleter.
293            pub fn leak(self) -> *mut $type {
294                let ptr = self.ptr.as_ptr();
295                std::mem::forget( self );
296                ptr
297            }
298        }
299
300        impl std::borrow::Borrow<$type> for $boxed_type {
301            fn borrow(&self) -> &$type {
302                self.as_ref()
303            }
304        }
305
306        impl Drop for $boxed_type {
307            fn drop(&mut self) {
308                unsafe {
309                    $delete_func( self.ptr.as_ptr() );
310                }
311            }
312        }
313
314        impl std::ops::Deref for $boxed_type {
315            type Target = $type;
316
317            fn deref(&self) -> &Self::Target {
318                unsafe{self.ptr.as_ref()}
319            }
320        }
321
322        impl std::ops::DerefMut for $boxed_type {
323            fn deref_mut(&mut self) -> &mut Self::Target {
324                unsafe{self.ptr.as_mut()}
325            }
326        }
327
328        impl AsRef<$type> for $boxed_type {
329            fn as_ref(&self) -> &$type {
330                unsafe{self.ptr.as_ref()}
331            }
332        }
333
334        impl AsMut<$type> for $boxed_type {
335            fn as_mut(&mut self) -> &mut $type {
336                unsafe{self.ptr.as_mut()}
337            }
338        }
339
340        $(ffi_box!(@impl, $type, $boxed_type, $func_type($func));)*
341    };
342}
343
344/// Generates iterator types for FFI containers.
345///
346/// # Example
347///
348/// ```no_run
349/// # #[macro_use] extern crate easy_ffi_wrapper;
350/// mod bindings {
351///     pub enum ContainerType {}
352///     pub enum ContainerItem {}
353///
354///     extern {
355///         pub fn container_name_len(c: *const ContainerType) -> usize;
356///         pub fn container_name_get(c: *const ContainerType, pos: usize) -> *const ContainerItem;
357///     }
358/// }
359///
360/// use bindings::{ContainerType, ContainerItem};
361///
362/// easy_ffi_wrapper::ffi_iter!(
363///     ContainerIter(ContainerType) -> ContainerItem,
364///     len(bindings::container_name_len),
365///     get(bindings::container_name_get)
366/// );
367/// ```
368///
369/// The generated type implements: `Iterator`, `DoubleEndedIterator`, `ExactSizeIterator`,
370/// `FusedIterator`. It can be created from the container type and exposes random access `index`
371/// function.
372///
373/// # Notes
374///
375/// The `std::ops::Index` trait cannot be implemented ergnomically due to the following issue:
376/// The item references returned by `Index::index` cannot outlive the iterator.
377/// In general `ffi_iter` is inappropriate for use with containers which already implement
378/// `Iterator` (for example, types in Rust `std` and `core`).
379#[macro_export]
380macro_rules! ffi_iter {
381    (@impl, struct, $iterator_type:ident($container:ident),) => {
382        #[derive(Clone)]
383        pub struct $iterator_type<'a> {
384            container: &'a $container,
385            pos: usize,
386            len: usize,
387        }
388    };
389    (@impl, struct, $iterator_type:ident($container:ident), mut) => {
390        pub struct $iterator_type<'a> {
391            container: &'a mut $container,
392            pos: usize,
393            len: usize,
394        }
395    };
396
397    (@impl, lifetime, $iterator_type:ident,) => {
398        $iterator_type<'a>
399    };
400    (@impl, lifetime, $iterator_type:ident, mut) => {
401        $iterator_type<'_>
402    };
403
404    ($iterator_type:ident($container:ident) -> $(($mutability:ident))? $type:ident, len($len_func:path), get($get_func:path)) => {
405        ffi_iter!(@impl, struct, $iterator_type($container), $($mutability)*);
406
407        impl<'a> $iterator_type<'a> {
408            /// Constructs new iterator from a given container.
409            ///
410            /// # Safety
411            ///
412            /// This function is unsafe since it uses the provided `$len_func` which is unsafe.
413            /// The safety guarantees are the same as of the `$len_func` function.
414            pub unsafe fn new(container: &'a $($mutability)* $container) -> Self {
415                Self {
416                    len: $len_func(container),
417                    container,
418                    pos: 0,
419                }
420            }
421
422            pub fn index(&$($mutability)* self, index: usize) -> &'a $type {
423                assert!(index + self.pos < self.len);
424                unsafe { &$($mutability)* *$get_func(self.container, index + self.pos) }
425            }
426
427            /// Slices this iterator by a given range.
428            ///
429            /// # Panics
430            ///
431            /// Panics if the range is outside of bounds of the iterator.
432            pub fn slice<R: std::ops::RangeBounds<usize>>(& $($mutability)* self, range: R) -> ffi_iter!(@impl, lifetime, $iterator_type, $($mutability)*) {
433                use std::ops::Bound;
434                let pos = match range.start_bound() {
435                    Bound::Included(&idx) => self.pos + idx,
436                    Bound::Excluded(&idx) => self.pos + idx + 1,
437                    Bound::Unbounded => self.pos,
438                };
439                let len = match range.end_bound() {
440                    Bound::Included(&idx) => self.pos + idx + 1,
441                    Bound::Excluded(&idx) => self.pos + idx,
442                    Bound::Unbounded => self.len,
443                };
444                $iterator_type {
445                    container: self.container,
446                    pos,
447                    len,
448                }
449            }
450        }
451
452        impl<'a> Iterator for $iterator_type<'a> {
453            type Item = &'a $($mutability)* $type;
454            fn next(&mut self) -> Option<Self::Item> {
455                if self.pos < self.len {
456                    let result = unsafe { &$($mutability)* *$get_func(self.container, self.pos) };
457                    self.pos += 1;
458                    Some(result)
459                } else {
460                    None
461                }
462            }
463
464            fn size_hint(&self) -> (usize, Option<usize>) {
465                (self.len - self.pos, Some(self.len - self.pos))
466            }
467        }
468
469        impl<'a> DoubleEndedIterator for $iterator_type<'a> {
470            fn next_back(&mut self) -> Option<Self::Item> {
471                if self.pos < self.len {
472                    let result = unsafe { &$($mutability)* *$get_func(self.container, self.len - 1) };
473                    self.len -= 1;
474                    Some(result)
475                } else {
476                    None
477                }
478            }
479        }
480
481        impl<'a> std::iter::FusedIterator for $iterator_type<'a> {}
482
483        impl<'a> ExactSizeIterator for $iterator_type<'a> {}
484    };
485}
486
487/// Generates iterator types for FFI containers.
488///
489/// # Example
490///
491/// ```rust,no_run
492/// # #[macro_use] extern crate easy_ffi_wrapper;
493/// mod bindings {
494///     pub enum ContainerType {}
495///     pub enum ContainerItem {}
496///
497///     extern {
498///         pub fn container_name_len(c: *const ContainerType) -> usize;
499///         pub fn container_name_get(c: *const ContainerType, pos: usize) -> *const ContainerItem;
500///         pub fn container_name_get_mut(c: *mut ContainerType, pos: usize) -> *mut ContainerItem;
501///         pub fn container_name_grow(c: *mut ContainerType) -> *mut ContainerItem;
502///         pub fn container_name_clear(c: *mut ContainerType);
503///     }
504/// }
505///
506/// use bindings::{ContainerType, ContainerItem};
507///
508/// easy_ffi_wrapper::ffi_vec!(
509///     ContainerType(ContainerIter, ContainerIterMut) -> ContainerItem,
510///     len(bindings::container_name_len),
511///     get(bindings::container_name_get),
512///     get_mut(bindings::container_name_get_mut),
513///     grow(bindings::container_name_grow),
514///     clear(bindings::container_name_clear)
515/// );
516/// ```
517#[macro_export]
518macro_rules! ffi_vec {
519    ($vec_type:ident($iter_type:ident, $iter_mut_type:ident) -> $type:ident,
520        len($len_func:path),
521        get($get_func:path),
522        get_mut($get_mut_func:path),
523        grow($grow_func:path),
524        clear($clear_func:path)) => {
525        $crate::ffi_iter!(
526          $iter_type($vec_type) -> $type,
527          len($len_func),
528          get($get_func)
529        );
530        $crate::ffi_iter!(
531          $iter_mut_type($vec_type) -> (mut) $type,
532          len($len_func),
533          get($get_mut_func)
534        );
535        impl $vec_type {
536            /// Returns an iterator over the content
537            pub fn iter(&self) -> $iter_type {
538                unsafe {$iter_type::new(self)}
539            }
540
541            /// Returns a mutable iterator over the content
542            pub fn iter_mut(&mut self) -> $iter_mut_type {
543                unsafe {$iter_mut_type::new(self)}
544            }
545
546            pub fn grow(&mut self) -> &mut $type {
547                unsafe {&mut *$grow_func(self)}
548            }
549
550            pub fn clear(&mut self) {
551                unsafe {$clear_func(self)};
552            }
553
554            pub fn len(&self) -> usize{
555                unsafe {$len_func(self)}
556            }
557
558            pub fn get(&self, index: usize) -> Option<&$type> {
559                if index >= self.len() {
560                    None
561                } else {
562                    unsafe {Some(&*$get_func(self, index))}
563                }
564            }
565
566            pub fn first(&self) -> Option<&$type> {
567                self.get(0)
568            }
569
570            pub fn first_mut(&mut self) -> Option<&mut $type> {
571                self.get_mut(0)
572            }
573
574            pub fn last(&self) -> Option<&$type> {
575                self.get(self.len().wrapping_sub(1))
576            }
577
578            pub fn last_mut(&mut self) -> Option<&mut $type> {
579                self.get_mut(self.len().wrapping_sub(1))
580            }
581
582            pub fn get_mut(&mut self, index: usize) -> Option<&mut $type> {
583                if index >= self.len() {
584                    None
585                } else {
586                    unsafe {Some(&mut *$get_mut_func(self, index))}
587                }
588            }
589        }
590
591        impl std::ops::Index<usize> for $vec_type {
592            type Output = $type;
593
594            fn index(&self, index: usize) -> &$type {
595                self.get(index).expect("Out of bounds")
596            }
597        }
598
599        impl std::ops::IndexMut<usize> for $vec_type {
600            fn index_mut(&mut self, index: usize) -> &mut $type {
601                self.get_mut(index).expect("Out of bounds")
602            }
603        }
604    };
605}
606
607#[cfg(test)]
608mod tests {
609    #![allow(dead_code)]
610    use super::*;
611
612    #[derive(Debug)]
613    pub struct A {}
614
615    unsafe fn create_a() -> *mut A {
616        Box::leak(Box::new(A {}))
617    }
618
619    unsafe fn delete_a(ptr: *mut A) {
620        std::mem::drop(Box::from_raw(ptr));
621    }
622
623    ffi_box!(A, BoxedA, debug, delete(delete_a), new(create_a));
624
625    #[test]
626    fn boxed_new() {
627        {
628            let _a = A::new();
629        }
630    }
631
632    #[test]
633    fn debug_a() {
634        format!("{:?}", A::new());
635    }
636
637    pub struct B {}
638
639    unsafe fn create_b() -> *mut B {
640        Box::leak(Box::new(B {}))
641    }
642
643    unsafe fn delete_b(ptr: *mut B) {
644        std::mem::drop(Box::from_raw(ptr));
645    }
646
647    ffi_box!(B, BoxedB, delete(delete_b));
648
649    #[test]
650    fn boxed_from_raw() {
651        {
652            let b = unsafe { BoxedB::from_raw(create_b()) };
653            unsafe {
654                delete_b(b.leak());
655            }
656        }
657    }
658
659    pub struct C {}
660
661    unsafe fn create_c() -> *mut C {
662        Box::leak(Box::new(C {}))
663    }
664
665    unsafe fn delete_c(ptr: *mut C) {
666        std::mem::drop(Box::from_raw(ptr));
667    }
668
669    unsafe fn clone_c(_ptr: *const C) -> *mut C {
670        Box::leak(Box::new(C {}))
671    }
672
673    ffi_box!(C, BoxedC, delete(delete_c), new(create_c), clone(clone_c));
674
675    #[test]
676    fn boxed_clone() {
677        {
678            let c = C::new();
679            let _d = c.clone();
680            let _e = (&c as &C).to_owned();
681        }
682    }
683
684    pub struct MyVec(Vec<usize>);
685
686    unsafe fn vec_len(ptr: *const MyVec) -> usize {
687        (*ptr).0.len()
688    }
689
690    unsafe fn vec_get(ptr: *const MyVec, index: usize) -> *const usize {
691        &(*ptr).0[index]
692    }
693
694    ffi_iter!(MyVecIter(MyVec) -> usize, len(vec_len), get(vec_get));
695
696    #[test]
697    fn iter() {
698        let data = MyVec(vec![0, 1, 2, 3, 4, 5, 6, 7]);
699        let data_rev = MyVec(data.0.iter().cloned().rev().collect());
700        let mut iter = unsafe { MyVecIter::new(&data) };
701        let collected: Vec<_> = iter.clone().cloned().collect();
702        assert_eq!(collected, data.0);
703        let collected_rev: Vec<_> = iter.clone().rev().cloned().collect();
704        assert_eq!(collected_rev, data_rev.0);
705
706        assert_eq!(data.0.len(), iter.len());
707        for x in 0..=7 {
708            assert_eq!(x, *iter.index(x));
709        }
710        iter.next();
711        assert_eq!(data.0.len() - 1, iter.len());
712        for x in 0..=6 {
713            assert_eq!(x + 1, *iter.index(x));
714        }
715
716        let x;
717        {
718            let iter_scoped = unsafe { MyVecIter::new(&data) };
719            x = iter_scoped.index(2);
720        }
721        assert_eq!(x, &data.0[2]);
722    }
723
724    #[test]
725    fn iter_slice() {
726        let data = MyVec(vec![0, 1, 2, 3, 4, 5, 6, 7]);
727        let iter = unsafe { MyVecIter::new(&data) };
728
729        let mut sliced_once = iter.slice(1..7);
730        let mut sliced_twice = sliced_once.slice(1..5);
731        assert_eq!(sliced_once.index(0), &1);
732        assert_eq!(sliced_once.index(5), &6);
733        assert_eq!(sliced_once.next(), Some(&1));
734        assert_eq!(sliced_once.next(), Some(&2));
735        assert_eq!(sliced_once.next(), Some(&3));
736        assert_eq!(sliced_once.next(), Some(&4));
737        assert_eq!(sliced_once.next(), Some(&5));
738        assert_eq!(sliced_once.next(), Some(&6));
739        assert_eq!(sliced_once.next(), None);
740
741        assert_eq!(sliced_twice.index(0), &2);
742        assert_eq!(sliced_twice.index(3), &5);
743        assert_eq!(sliced_twice.next(), Some(&2));
744        assert_eq!(sliced_twice.next(), Some(&3));
745        assert_eq!(sliced_twice.next(), Some(&4));
746        assert_eq!(sliced_twice.next(), Some(&5));
747        assert_eq!(sliced_twice.next(), None);
748
749        let sliced_unbounded = iter.slice(..);
750        assert_eq!(sliced_unbounded.index(0), &0);
751        assert_eq!(sliced_unbounded.index(7), &7);
752        assert_eq!(sliced_unbounded.copied().collect::<Vec<_>>(), data.0);
753
754        let sliced_inclusive = iter.slice(0..=7);
755        assert_eq!(sliced_inclusive.index(0), &0);
756        assert_eq!(sliced_inclusive.index(7), &7);
757        assert_eq!(sliced_inclusive.copied().collect::<Vec<_>>(), data.0);
758    }
759
760    #[test]
761    fn empty_str() {
762        let empty1 = unsafe { Str::from_raw_parts(std::ptr::null(), 10) };
763        assert_eq!(empty1.bytes(), b"");
764        let empty2 = Some(unsafe { Str::from_raw_parts(std::ptr::null(), 10) });
765        assert!(empty2.is_some()); // This would fail for unchecked slices and just eval to `None`
766    }
767
768    #[test]
769    fn str_utf8() {
770        let str_ascii =
771            unsafe { Str::from_raw_parts(b"abcde" as *const _ as *const std::os::raw::c_char, 5) };
772        assert_eq!(str_ascii.to_str(), Ok("abcde"));
773        let str_utf8 = unsafe {
774            Str::from_raw_parts(
775                b"abc\xce\xb1de" as *const _ as *const std::os::raw::c_char,
776                7,
777            )
778        };
779        assert_eq!(str_utf8.to_str(), Ok("abcαde"));
780        assert_eq!(
781            str_utf8.to_str_lossy(),
782            std::borrow::Cow::Borrowed("abcαde")
783        );
784        let str_invalid_utf8 = unsafe {
785            Str::from_raw_parts(
786                b"abc\x00\xb1de" as *const _ as *const std::os::raw::c_char,
787                7,
788            )
789        };
790        assert!(str_invalid_utf8.to_str().is_err());
791        match str_invalid_utf8.to_str_lossy() {
792            std::borrow::Cow::Owned(x) => {
793                assert_eq!(x, String::from("abc\0�de"));
794            }
795            _ => panic!("UTF decoding should have failed"),
796        }
797    }
798
799    #[test]
800    fn str_builder() {
801        struct A {}
802
803        impl A {
804            fn to_str_with_bound_lifetime(&self) -> &str {
805                let mut result = StrBuilder::new();
806                result.ptr = b"bla".as_ptr() as *const _;
807                result.len = 3;
808
809                unsafe { result.build().to_str().unwrap() }
810            }
811        }
812    }
813
814    unsafe fn vec_get_mut(c: *mut MyVec, pos: usize) -> *mut usize {
815        &mut (*c).0[pos]
816    }
817    unsafe fn vec_grow(c: *mut tests::MyVec) -> *mut usize {
818        (*c).0.push(Default::default());
819        &mut *(*c).0.last_mut().unwrap()
820    }
821    unsafe fn vec_clear(c: *mut MyVec) {
822        (*c).0.clear();
823    }
824
825    ffi_vec!(
826        MyVec(MyVecIterConst, MyVecIterMut) -> usize,
827        len(vec_len),
828        get(vec_get),
829        get_mut(vec_get_mut),
830        grow(vec_grow),
831        clear(vec_clear)
832    );
833
834    #[test]
835    fn vec() {
836        let mut data = MyVec(vec![0, 1, 2, 3, 4, 5, 6, 7]);
837        assert_eq!(data.len(), 8);
838        data[0] = 10;
839        assert_eq!(data[0], 10);
840        assert_eq!(data.first(), Some(&10));
841        *data.last_mut().unwrap() = 99;
842        assert_eq!(data[7], 99);
843        assert_eq!(data.last(), Some(&99));
844        data.clear();
845        assert_eq!(data.len(), 0);
846        *data.grow() = 100;
847        assert_eq!(data.len(), 1);
848        assert_eq!(data[0], 100);
849    }
850}