Skip to main content

foreign/impl/
cow.rs

1use std::borrow::Cow;
2
3use crate::foreign::*;
4
5impl<'a, B> FreeForeign for Cow<'a, B>
6where
7    B: 'a + ToOwned + ?Sized + FreeForeign,
8{
9    type Foreign = B::Foreign;
10
11    unsafe fn free_foreign(ptr: *mut B::Foreign) {
12        B::free_foreign(ptr);
13    }
14}
15
16impl<'a, B> CloneToForeign for Cow<'a, B>
17where
18    B: 'a + ToOwned + ?Sized + CloneToForeign,
19{
20    fn clone_to_foreign(&self) -> OwnedPointer<Self> {
21        (**self).clone_to_foreign().into()
22    }
23}
24
25impl<'s, B> BorrowForeign for Cow<'s, B>
26where
27    B: 's + ToOwned + ?Sized + BorrowForeign,
28{
29    type Storage<'a>
30        = B::Storage<'a>
31    where
32        Self: 'a;
33
34    fn borrow_foreign(&self) -> BorrowedPointer<Self, Self::Storage<'_>> {
35        (**self).borrow_foreign().into()
36    }
37}
38
39impl<'a, B> FromForeign for Cow<'a, B>
40where
41    B: 'a + ToOwned + ?Sized + FreeForeign,
42    <B as ToOwned>::Owned: FromForeign + FreeForeign<Foreign = B::Foreign>,
43{
44    unsafe fn cloned_from_foreign(ptr: *const B::Foreign) -> Self {
45        let cloned: <B as ToOwned>::Owned = FromForeign::cloned_from_foreign(ptr);
46        Cow::Owned(cloned)
47    }
48}
49
50impl<'a, B> IntoForeign for Cow<'a, B>
51where
52    B: 'a + ToOwned + ?Sized + FreeForeign,
53    <B as ToOwned>::Owned: IntoForeign + FreeForeign<Foreign = B::Foreign>,
54{
55    type Storage = <B::Owned as IntoForeign>::Storage;
56
57    fn into_foreign(self) -> BorrowedMutPointer<Self, Self::Storage> {
58        self.into_owned().into_foreign().into()
59    }
60}
61
62#[allow(clippy::undocumented_unsafe_blocks)]
63#[cfg(test)]
64mod tests {
65    use std::borrow::Cow;
66    use std::ffi::{c_void, CStr};
67
68    use crate::c_str::c_str;
69    use crate::foreign::*;
70
71    #[test]
72    fn test_cloned_from_foreign_string_cow() {
73        let s = "Hello, world!".to_string();
74        let cstr = c_str!("Hello, world!");
75        let cloned = unsafe { Cow::cloned_from_foreign(cstr.as_ptr()) };
76        assert_eq!(s, cloned);
77    }
78
79    #[test]
80    fn test_clone_to_foreign_string_cow() {
81        let p = c_str!("Hello, world!").as_ptr();
82        for s in [
83            Into::<Cow<str>>::into("Hello, world!"),
84            Into::<Cow<str>>::into("Hello, world!".to_string()),
85        ] {
86            let cloned = s.clone_to_foreign();
87            unsafe {
88                let len = libc::strlen(cloned.as_ptr());
89                assert_eq!(len, s.len());
90                assert_eq!(
91                    libc::memcmp(
92                        cloned.as_ptr().cast::<c_void>(),
93                        p.cast::<c_void>(),
94                        len + 1
95                    ),
96                    0
97                );
98            }
99        }
100    }
101
102    #[test]
103    fn test_borrow_foreign_string_cow() {
104        let p = c_str!("Hello, world!").as_ptr();
105        for s in [
106            Into::<Cow<CStr>>::into(c_str!("Hello, world!")),
107            Into::<Cow<CStr>>::into(c_str!("Hello, world!").to_owned()),
108        ] {
109            let borrowed = s.borrow_foreign();
110            unsafe {
111                let len = libc::strlen(borrowed.as_ptr());
112                assert_eq!(len, libc::strlen(p));
113                assert_eq!(
114                    libc::memcmp(
115                        borrowed.as_ptr().cast::<c_void>(),
116                        p.cast::<c_void>(),
117                        len + 1
118                    ),
119                    0
120                );
121            }
122        }
123    }
124
125    #[test]
126    fn test_into_foreign_string_cow() {
127        let p = c_str!("Hello, world!").as_ptr();
128        for s in [
129            Into::<Cow<str>>::into("Hello, world!"),
130            Into::<Cow<str>>::into("Hello, world!".to_string()),
131        ] {
132            let consumed = s.into_foreign();
133            unsafe {
134                let len = libc::strlen(consumed.as_ptr());
135                assert_eq!(len, libc::strlen(p));
136                assert_eq!(
137                    libc::memcmp(
138                        consumed.as_ptr().cast::<c_void>(),
139                        p.cast::<c_void>(),
140                        len + 1
141                    ),
142                    0
143                );
144            }
145        }
146    }
147}