couchbase_lite_core_sys/
helpers.rs1use crate::{
4 C4CollectionSpec, C4String, FLHeapSlice, FLSlice, FLSliceResult, FLSliceResult_Release,
5 FLString,
6};
7use std::{borrow::Cow, os::raw::c_void, ptr, slice, str};
8
9impl Default for FLSlice {
10 #[inline]
11 fn default() -> Self {
12 Self {
13 buf: ptr::null(),
14 size: 0,
15 }
16 }
17}
18
19impl<'a> From<&'a str> for FLSlice {
20 #[inline]
21 fn from(s: &'a str) -> Self {
22 Self {
23 buf: if !s.is_empty() {
24 s.as_ptr() as *const c_void
25 } else {
26 ptr::null()
27 },
28 size: s.len(),
29 }
30 }
31}
32
33impl<'a> From<&'a [u8]> for FLSlice {
34 #[inline]
35 fn from(ba: &'a [u8]) -> Self {
36 Self {
37 buf: if !ba.is_empty() {
38 ba.as_ptr() as *const c_void
39 } else {
40 ptr::null()
41 },
42 size: ba.len(),
43 }
44 }
45}
46
47impl From<FLSlice> for &[u8] {
48 #[inline]
49 fn from(s: FLSlice) -> Self {
50 if s.size != 0 {
51 unsafe { slice::from_raw_parts(s.buf as *const u8, s.size) }
52 } else {
53 &[]
56 }
57 }
58}
59
60impl Drop for FLSliceResult {
61 #[inline]
62 fn drop(&mut self) {
63 unsafe {
64 FLSliceResult_Release(FLSliceResult {
65 buf: self.buf,
66 size: self.size,
67 })
68 };
69 }
70}
71
72impl Default for FLSliceResult {
73 #[inline]
74 fn default() -> Self {
75 Self {
76 buf: ptr::null(),
77 size: 0,
78 }
79 }
80}
81
82impl AsRef<[u8]> for FLSliceResult {
83 #[inline]
84 fn as_ref(&self) -> &[u8] {
85 self.as_bytes()
86 }
87}
88
89unsafe impl Send for FLSliceResult {}
91
92impl FLSliceResult {
93 #[inline]
94 pub fn as_bytes(&self) -> &[u8] {
95 if self.size != 0 {
96 unsafe { slice::from_raw_parts(self.buf as *const u8, self.size) }
97 } else {
98 &[]
101 }
102 }
103 #[inline]
104 pub fn as_utf8_lossy(&self) -> Cow<'_, str> {
105 String::from_utf8_lossy(self.as_bytes())
106 }
107 #[inline]
108 pub fn is_empty(&self) -> bool {
109 self.size == 0
110 }
111 #[inline]
112 pub fn as_fl_slice(&self) -> FLSlice {
113 FLSlice {
114 buf: self.buf,
115 size: self.size,
116 }
117 }
118}
119
120impl<'a> TryFrom<FLString> for &'a str {
121 type Error = str::Utf8Error;
122 #[inline]
123 fn try_from(value: FLString) -> Result<Self, Self::Error> {
124 let bytes: &'a [u8] = value.into();
125 str::from_utf8(bytes)
126 }
127}
128
129impl FLHeapSlice {
130 #[inline]
131 pub fn as_fl_slice(&self) -> FLSlice {
132 *self
133 }
134}
135
136macro_rules! flstr {
139 ($str:expr) => {
140 C4String {
141 buf: $str.as_bytes().as_ptr() as *const c_void,
142 size: $str.as_bytes().len() - 1,
143 }
144 };
145}
146
147#[allow(non_upper_case_globals)]
149pub const kC4DefaultScopeID: C4String = flstr!("_default\0");
150
151#[allow(non_upper_case_globals)]
153pub const kC4DefaultCollectionName: C4String = flstr!("_default\0");
154
155#[allow(non_upper_case_globals)]
156pub const kC4DefaultCollectionSpec: C4CollectionSpec = C4CollectionSpec {
157 name: kC4DefaultCollectionName,
158 scope: kC4DefaultScopeID,
159};
160
161#[test]
162fn test_null_slice_handling() {
163 let ffi_null_slice = FLSlice {
164 buf: ptr::null(),
165 size: 0,
166 };
167 let slice: &[u8] = ffi_null_slice.into();
168 assert!(slice.is_empty());
169
170 let ffi_null_slice: FLSliceResult = unsafe { crate::FLSliceResult_New(0) };
171 let slice: &[u8] = ffi_null_slice.as_bytes();
172 assert!(slice.is_empty());
173
174 let ffi_null_slice = FLSliceResult {
175 buf: ptr::null(),
176 size: 0,
177 };
178 let slice: &[u8] = ffi_null_slice.as_bytes();
179 assert!(slice.is_empty());
180}