1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 // Mask for cffi purpose.
17 #![allow(non_camel_case_types)]
18
19 pub(crate) mod basic_rust_types;
20 pub(crate) mod cloud_ext_types;
21 pub(crate) mod cloud_extension;
22
23 use basic_rust_types::*;
24 use cloud_ext_types::*;
25
26 use std::ffi::{c_int, c_uchar, c_uint, c_void};
27 use std::ptr::slice_from_raw_parts;
28
29 /// Errno of success.
30 pub const ERRNO_SUCCESS: c_int = 0;
31 /// Errno of null pointer.
32 pub const ERRNO_NULLPTR: c_int = 1;
33 /// Errno of wrong type.
34 pub const ERRNO_WRONG_TYPE: c_int = 2;
35 /// Errno of invalid input type.
36 pub const ERRNO_INVALID_INPUT_TYPE: c_int = 3;
37 /// Errno of asset download failure.
38 pub const ERRNO_ASSET_DOWNLOAD_FAILURE: c_int = 4;
39 /// Errno of asset upload failure.
40 pub const ERRNO_ASSET_UPLOAD_FAILURE: c_int = 5;
41 /// Errno of unsupported feature.
42 pub const ERRNO_UNSUPPORTED: c_int = 6;
43 /// Errno of network error.
44 pub const ERRNO_NETWORK_ERROR: c_int = 7;
45 /// Errno of lock conflict.
46 pub const ERRNO_LOCKED_BY_OTHERS: c_int = 8;
47 /// Errno of locking action on unlocked cloud database.
48 pub const ERRNO_UNLOCKED: c_int = 9;
49 /// Errno of record limit exceeding.
50 pub const ERRNO_RECORD_LIMIT_EXCEEDED: c_int = 10;
51 /// Errno of no space for assets.
52 pub const ERRNO_NO_SPACE_FOR_ASSET: c_int = 11;
53 /// Errno of ipc read / write parcel error.
54 pub const ERRNO_IPC_RW_ERROR: c_int = 12;
55 /// Errno of IPC connection error.
56 pub const ERRNO_IPC_CONN_ERROR: c_int = 13;
57 /// Errno of batch of ipc errors.
58 pub const ERRNO_IPC_ERRORS: c_int = 14;
59 /// Errno of other io error.
60 pub const ERRNO_OTHER_IO_ERROR: c_int = 15;
61 /// Errno of array out of range.
62 pub const ERRNO_OUT_OF_RANGE: c_int = 16;
63 /// Errno of no target table in source database.
64 pub const ERRNO_NO_SUCH_TABLE_IN_DB: c_int = 17;
65 /// Errno of invalid status of the cloud
66 pub const ERRNO_CLOUD_INVALID_STATUS: c_int = 18;
67 /// Errno of unknown error.
68 pub const ERRNO_UNKNOWN: c_int = 19;
69 /// Errno of cloud disabling
70 pub const ERRNO_CLOUD_DISABLE: c_int = 20;
71 /// Errno of invalid key
72 pub const ERRNO_INVALID_KEY: c_int = 21;
73
74 #[derive(Copy, Clone)]
75 pub(crate) enum SafetyCheckId {
76 // Arbitrarily defined id, used for type safety check
77 Vector = 32_isize,
78 HashMap = 33,
79 Value = 34,
80 CloudAsset = 35,
81 Database = 36,
82 CloudInfo = 37,
83 AppInfo = 38,
84 Table = 39,
85 Field = 40,
86 SchemaMeta = 41,
87 RelationSet = 42,
88 CloudDbData = 43,
89 ValueBucket = 44,
90 CloudAssetLoader = 45,
91 CloudDatabase = 46,
92 CloudSync = 47,
93 }
94
95 impl SafetyCheckId {
as_usize(&self) -> usize96 pub(crate) fn as_usize(&self) -> usize {
97 *self as usize
98 }
99 }
100
type_safety_check(ptr: *const c_void, tar_type: SafetyCheckId) -> bool101 pub(crate) unsafe fn type_safety_check(ptr: *const c_void, tar_type: SafetyCheckId) -> bool {
102 if ptr.is_null() {
103 return false;
104 }
105 // Read the id, if possible
106 let src = &*(ptr as *const usize);
107 *src == tar_type.as_usize()
108 }
109
110 /// Wrapper of Rust struct. Add id for safety requirements, pointers passed in will be checked
111 /// according to this id.
112 #[repr(C)]
113 pub struct SafeCffiWrapper<T> {
114 id: usize,
115 inner: T,
116 }
117
118 impl<T> SafeCffiWrapper<T> {
new(inner: T, tar_type: SafetyCheckId) -> SafeCffiWrapper<T>119 pub(crate) fn new(inner: T, tar_type: SafetyCheckId) -> SafeCffiWrapper<T> {
120 SafeCffiWrapper {
121 id: tar_type.as_usize(),
122 inner,
123 }
124 }
125
into_ptr(self) -> *mut SafeCffiWrapper<T>126 pub(crate) fn into_ptr(self) -> *mut SafeCffiWrapper<T> {
127 Box::into_raw(Box::new(self))
128 }
129
from_ptr( src: *mut SafeCffiWrapper<T>, typ: SafetyCheckId, ) -> Option<SafeCffiWrapper<T>>130 pub(crate) unsafe fn from_ptr(
131 src: *mut SafeCffiWrapper<T>,
132 typ: SafetyCheckId,
133 ) -> Option<SafeCffiWrapper<T>> {
134 src.as_mut().map(|obj| {
135 type_safety_check(obj as *const _ as *const c_void, typ)
136 .then_some(*Box::from_raw(obj as *mut SafeCffiWrapper<T>))
137 })?
138 }
139
get_inner_ref( src: *const SafeCffiWrapper<T>, typ: SafetyCheckId, ) -> Option<&'static T>140 pub(crate) unsafe fn get_inner_ref(
141 src: *const SafeCffiWrapper<T>,
142 typ: SafetyCheckId,
143 ) -> Option<&'static T> {
144 if let Some(obj) = src.as_ref() {
145 if type_safety_check(obj as *const _ as *const c_void, typ) {
146 let wrapper = &*src;
147 return Some(&wrapper.inner);
148 }
149 }
150 None
151 }
152
get_inner_mut( src: *mut SafeCffiWrapper<T>, typ: SafetyCheckId, ) -> Option<&'static mut T>153 pub(crate) unsafe fn get_inner_mut(
154 src: *mut SafeCffiWrapper<T>,
155 typ: SafetyCheckId,
156 ) -> Option<&'static mut T> {
157 if let Some(obj) = src.as_mut() {
158 if type_safety_check(obj as *const _ as *const c_void, typ) {
159 let wrapper = &mut *src;
160 return Some(&mut wrapper.inner);
161 }
162 }
163 None
164 }
165
get_inner(src: *mut SafeCffiWrapper<T>, typ: SafetyCheckId) -> Option<T>166 pub(crate) unsafe fn get_inner(src: *mut SafeCffiWrapper<T>, typ: SafetyCheckId) -> Option<T> {
167 SafeCffiWrapper::<T>::from_ptr(src, typ).map(|x| x.inner)
168 }
169 }
170
171 /// Transform a pointer of c char array and its length to a String.
172 ///
173 /// # Safety
174 /// Users should guarantee that String doesn't contain non-UTF8 literals, and the length passed
175 /// in is valid to avoid memory issues and undefined behaviors.
char_ptr_to_string(ptr: *const c_uchar, len: c_uint) -> String176 pub(crate) unsafe fn char_ptr_to_string(ptr: *const c_uchar, len: c_uint) -> String {
177 if ptr.is_null() {
178 return String::default();
179 }
180 let slice = &(*slice_from_raw_parts(ptr, len as usize));
181 String::from_utf8_unchecked(slice.to_vec())
182 }
183
184 #[cfg(test)]
185 mod test {
186 use crate::c_adapter::*;
187 use std::collections::HashMap;
188
189 /// UT test for type wrapper.
190 ///
191 /// # Title
192 /// ut_wrapper
193 ///
194 /// # Brief
195 /// 1. Pass in type with wrong id.
196 /// 2. Process should not panic, but return Option successfully.
197 #[test]
ut_wrapper()198 fn ut_wrapper() {
199 unsafe {
200 let mut src = 3;
201 let mut wrong_typ = 1_usize;
202 assert_eq!(
203 OhCloudExtVectorPush(
204 &mut wrong_typ as *mut _ as *mut OhCloudExtVector,
205 &mut src as *mut _ as *mut c_void,
206 0
207 ),
208 ERRNO_WRONG_TYPE
209 );
210
211 let map = HashMapCffi::U32(HashMap::new());
212 let mut wrong_map = OhCloudExtHashMap::new(map, SafetyCheckId::HashMap);
213 assert_eq!(
214 OhCloudExtVectorPush(
215 &mut wrong_map as *mut _ as *mut OhCloudExtVector,
216 &mut src as *mut _ as *mut c_void,
217 0
218 ),
219 ERRNO_WRONG_TYPE
220 );
221
222 let vec = OhCloudExtVectorNew(OhCloudExtRustType::I32);
223 assert!(!vec.is_null());
224 assert_eq!(
225 OhCloudExtVectorPush(vec, &mut src as *mut _ as *mut c_void, 0),
226 ERRNO_SUCCESS
227 );
228 OhCloudExtVectorFree(vec);
229 }
230 }
231 }
232