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}