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 FLSliceResult {
83 #[inline]
84 pub fn as_bytes(&self) -> &[u8] {
85 if self.size != 0 {
86 unsafe { slice::from_raw_parts(self.buf as *const u8, self.size) }
87 } else {
88 &[]
91 }
92 }
93 #[inline]
94 pub fn as_utf8_lossy(&self) -> Cow<'_, str> {
95 String::from_utf8_lossy(self.as_bytes())
96 }
97 #[inline]
98 pub fn is_empty(&self) -> bool {
99 self.size == 0
100 }
101 #[inline]
102 pub fn as_fl_slice(&self) -> FLSlice {
103 FLSlice {
104 buf: self.buf,
105 size: self.size,
106 }
107 }
108}
109
110impl<'a> TryFrom<FLString> for &'a str {
111 type Error = str::Utf8Error;
112 #[inline]
113 fn try_from(value: FLString) -> Result<Self, Self::Error> {
114 let bytes: &'a [u8] = value.into();
115 str::from_utf8(bytes)
116 }
117}
118
119impl FLHeapSlice {
120 #[inline]
121 pub fn as_fl_slice(&self) -> FLSlice {
122 *self
123 }
124}
125
126macro_rules! flstr {
129 ($str:expr) => {
130 C4String {
131 buf: $str.as_bytes().as_ptr() as *const c_void,
132 size: $str.as_bytes().len() - 1,
133 }
134 };
135}
136
137#[allow(non_upper_case_globals)]
139pub const kC4DefaultScopeID: C4String = flstr!("_default\0");
140
141#[allow(non_upper_case_globals)]
143pub const kC4DefaultCollectionName: C4String = flstr!("_default\0");
144
145#[allow(non_upper_case_globals)]
146pub const kC4DefaultCollectionSpec: C4CollectionSpec = C4CollectionSpec {
147 name: kC4DefaultCollectionName,
148 scope: kC4DefaultScopeID,
149};
150
151#[test]
152fn test_null_slice_handling() {
153 let ffi_null_slice = FLSlice {
154 buf: ptr::null(),
155 size: 0,
156 };
157 let slice: &[u8] = ffi_null_slice.into();
158 assert!(slice.is_empty());
159
160 let ffi_null_slice: FLSliceResult = unsafe { crate::FLSliceResult_New(0) };
161 let slice: &[u8] = ffi_null_slice.as_bytes();
162 assert!(slice.is_empty());
163
164 let ffi_null_slice = FLSliceResult {
165 buf: ptr::null(),
166 size: 0,
167 };
168 let slice: &[u8] = ffi_null_slice.as_bytes();
169 assert!(slice.is_empty());
170}