• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //! This module implements the function of Asset SDK from C to RUST.
17 
18 use core::ffi::c_void;
19 use std::{convert::TryFrom, mem::size_of, result::Result, slice};
20 
21 use asset_log::loge;
22 use asset_sdk::{log_throw_error, AssetError, AssetMap, Conversion, DataType, ErrCode, Manager, Tag, Value};
23 
24 const RESULT_CODE_SUCCESS: i32 = 0;
25 extern "C" {
AssetMalloc(size: u32) -> *mut c_void26     fn AssetMalloc(size: u32) -> *mut c_void;
27 }
28 
into_map(attributes: *const AssetAttr, attr_cnt: u32) -> Option<AssetMap>29 fn into_map(attributes: *const AssetAttr, attr_cnt: u32) -> Option<AssetMap> {
30     if attributes.is_null() && attr_cnt != 0 {
31         loge!("[FATAL][RUST SDK]Attributes is null.");
32         return None;
33     }
34 
35     let mut map = AssetMap::with_capacity(attr_cnt as usize);
36     for i in 0..attr_cnt {
37         unsafe {
38             let attr = attributes.add(i as usize);
39             let attr_tag = match Tag::try_from((*attr).tag) {
40                 Ok(tag) => tag,
41                 Err(_) => return None,
42             };
43             match attr_tag.data_type() {
44                 DataType::Bool => {
45                     map.insert(attr_tag, Value::Bool((*attr).value.boolean));
46                 },
47                 DataType::Number => {
48                     map.insert(attr_tag, Value::Number((*attr).value.uint32));
49                 },
50                 DataType::Bytes => {
51                     if (*attr).value.blob.data.is_null() || (*attr).value.blob.size == 0 {
52                         loge!("[FATAL][RUST SDK]Blob data is empty.");
53                         return None;
54                     }
55                     let blob_slice = slice::from_raw_parts((*attr).value.blob.data, (*attr).value.blob.size as usize);
56                     let blob_vec = blob_slice.to_vec();
57                     map.insert(attr_tag, Value::Bytes(blob_vec));
58                 },
59             };
60         }
61     }
62     Some(map)
63 }
64 
65 /// Function called from C programming language to Rust programming language for adding Asset.
66 #[no_mangle]
add_asset(attributes: *const AssetAttr, attr_cnt: u32) -> i3267 pub extern "C" fn add_asset(attributes: *const AssetAttr, attr_cnt: u32) -> i32 {
68     let map = match into_map(attributes, attr_cnt) {
69         Some(map) => map,
70         None => return ErrCode::InvalidArgument as i32,
71     };
72 
73     let manager = match Manager::build() {
74         Ok(manager) => manager,
75         Err(e) => return e.code as i32,
76     };
77 
78     if let Err(e) = manager.add(&map) {
79         e.code as i32
80     } else {
81         RESULT_CODE_SUCCESS
82     }
83 }
84 
85 /// Function called from C programming language to Rust programming language for removing Asset.
86 #[no_mangle]
remove_asset(query: *const AssetAttr, query_cnt: u32) -> i3287 pub extern "C" fn remove_asset(query: *const AssetAttr, query_cnt: u32) -> i32 {
88     let map = match into_map(query, query_cnt) {
89         Some(map) => map,
90         None => return ErrCode::InvalidArgument as i32,
91     };
92 
93     let manager = match Manager::build() {
94         Ok(manager) => manager,
95         Err(e) => return e.code as i32,
96     };
97 
98     if let Err(e) = manager.remove(&map) {
99         e.code as i32
100     } else {
101         RESULT_CODE_SUCCESS
102     }
103 }
104 
105 /// Function called from C programming language to Rust programming language for updating Asset.
106 #[no_mangle]
update_asset( query: *const AssetAttr, query_cnt: u32, attrs_to_update: *const AssetAttr, update_cnt: u32, ) -> i32107 pub extern "C" fn update_asset(
108     query: *const AssetAttr,
109     query_cnt: u32,
110     attrs_to_update: *const AssetAttr,
111     update_cnt: u32,
112 ) -> i32 {
113     let query_map = match into_map(query, query_cnt) {
114         Some(map) => map,
115         None => return ErrCode::InvalidArgument as i32,
116     };
117 
118     let update_map = match into_map(attrs_to_update, update_cnt) {
119         Some(map) => map,
120         None => return ErrCode::InvalidArgument as i32,
121     };
122 
123     let manager = match Manager::build() {
124         Ok(manager) => manager,
125         Err(e) => return e.code as i32,
126     };
127 
128     if let Err(e) = manager.update(&query_map, &update_map) {
129         e.code as i32
130     } else {
131         RESULT_CODE_SUCCESS
132     }
133 }
134 
135 /// Function called from C programming language to Rust programming language for pre querying Asset.
136 ///
137 /// # Safety
138 ///
139 /// The caller must ensure that the challenge pointer is valid.
140 #[no_mangle]
pre_query_asset(query: *const AssetAttr, query_cnt: u32, challenge: *mut AssetBlob) -> i32141 pub unsafe extern "C" fn pre_query_asset(query: *const AssetAttr, query_cnt: u32, challenge: *mut AssetBlob) -> i32 {
142     let map = match into_map(query, query_cnt) {
143         Some(map) => map,
144         None => return ErrCode::InvalidArgument as i32,
145     };
146 
147     if challenge.is_null() {
148         loge!("[FATAL][RUST SDK]challenge is null");
149         return ErrCode::InvalidArgument as i32;
150     }
151 
152     let manager = match Manager::build() {
153         Ok(manager) => manager,
154         Err(e) => return e.code as i32,
155     };
156 
157     let res = match manager.pre_query(&map) {
158         Err(e) => return e.code as i32,
159         Ok(res) => res,
160     };
161 
162     match AssetBlob::try_from(&res) {
163         Err(e) => e.code as i32,
164         Ok(b) => {
165             *challenge = b;
166             RESULT_CODE_SUCCESS
167         },
168     }
169 }
170 
171 /// Function called from C programming language to Rust programming language for querying Asset.
172 ///
173 /// # Safety
174 ///
175 /// The caller must ensure that the result_set pointer is valid.
176 #[no_mangle]
query_asset(query: *const AssetAttr, query_cnt: u32, result_set: *mut AssetResultSet) -> i32177 pub unsafe extern "C" fn query_asset(query: *const AssetAttr, query_cnt: u32, result_set: *mut AssetResultSet) -> i32 {
178     let map = match into_map(query, query_cnt) {
179         Some(map) => map,
180         None => return ErrCode::InvalidArgument as i32,
181     };
182 
183     if result_set.is_null() {
184         loge!("[FATAL][RUST SDK]result set is null");
185         return ErrCode::InvalidArgument as i32;
186     }
187 
188     let manager = match Manager::build() {
189         Ok(manager) => manager,
190         Err(e) => return e.code as i32,
191     };
192 
193     let res = match manager.query(&map) {
194         Err(e) => return e.code as i32,
195         Ok(res) => res,
196     };
197 
198     match AssetResultSet::try_from(&res) {
199         Err(e) => e.code as i32,
200         Ok(s) => {
201             *result_set = s;
202             RESULT_CODE_SUCCESS
203         },
204     }
205 }
206 
207 /// Function called from C programming language to Rust programming language for post quering Asset.
208 #[no_mangle]
post_query_asset(handle: *const AssetAttr, handle_cnt: u32) -> i32209 pub extern "C" fn post_query_asset(handle: *const AssetAttr, handle_cnt: u32) -> i32 {
210     let map = match into_map(handle, handle_cnt) {
211         Some(map) => map,
212         None => return ErrCode::InvalidArgument as i32,
213     };
214 
215     let manager = match Manager::build() {
216         Ok(manager) => manager,
217         Err(e) => return e.code as i32,
218     };
219 
220     if let Err(e) = manager.post_query(&map) {
221         e.code as i32
222     } else {
223         RESULT_CODE_SUCCESS
224     }
225 }
226 
227 /// Attribute of Asset with a c representation.
228 #[repr(C)]
229 pub struct AssetAttr {
230     tag: u32,
231     value: AssetValue,
232 }
233 
234 /// Blob of Asset with a c representation.
235 #[repr(C)]
236 #[derive(Clone, Copy)]
237 pub struct AssetBlob {
238     size: u32,
239     data: *mut u8,
240 }
241 
242 impl TryFrom<&Vec<u8>> for AssetBlob {
243     type Error = AssetError;
244 
try_from(vec: &Vec<u8>) -> Result<Self, Self::Error>245     fn try_from(vec: &Vec<u8>) -> Result<Self, Self::Error> {
246         let mut blob = AssetBlob { size: vec.len() as u32, data: std::ptr::null_mut() };
247 
248         blob.data = unsafe { AssetMalloc(blob.size) as *mut u8 };
249         if blob.data.is_null() {
250             return log_throw_error!(
251                 ErrCode::OutOfMemory,
252                 "[FATAL][RUST SDK]Unable to allocate memory for Asset_Blob."
253             );
254         }
255         unsafe { std::ptr::copy_nonoverlapping(vec.as_ptr(), blob.data, blob.size as usize) };
256         Ok(blob)
257     }
258 }
259 
260 #[repr(C)]
261 union AssetValue {
262     boolean: bool,
263     uint32: u32,
264     blob: AssetBlob,
265 }
266 
267 impl TryFrom<&Value> for AssetValue {
268     type Error = AssetError;
269 
try_from(value: &Value) -> Result<Self, Self::Error>270     fn try_from(value: &Value) -> Result<Self, Self::Error> {
271         let mut out = AssetValue { boolean: false };
272         match value {
273             Value::Bool(v) => out.boolean = *v,
274             Value::Number(v) => out.uint32 = *v,
275             Value::Bytes(v) => out.blob = AssetBlob::try_from(v)?,
276         }
277         Ok(out)
278     }
279 }
280 
281 #[repr(C)]
282 struct AssetResult {
283     count: u32,
284     attrs: *mut AssetAttr,
285 }
286 
287 impl TryFrom<&AssetMap> for AssetResult {
288     type Error = AssetError;
289 
try_from(map: &AssetMap) -> Result<Self, Self::Error>290     fn try_from(map: &AssetMap) -> Result<Self, Self::Error> {
291         let mut result = AssetResult { count: map.len() as u32, attrs: std::ptr::null_mut() };
292 
293         result.attrs =
294             unsafe { AssetMalloc(result.count.wrapping_mul(size_of::<AssetAttr>() as u32)) as *mut AssetAttr };
295         if result.attrs.is_null() {
296             return log_throw_error!(
297                 ErrCode::OutOfMemory,
298                 "[FATAL][RUST SDK]Unable to allocate memory for Asset_Result."
299             );
300         }
301 
302         for (i, (tag, value)) in map.iter().enumerate() {
303             unsafe {
304                 let attr = result.attrs.add(i);
305                 (*attr).tag = *tag as u32;
306                 (*attr).value = AssetValue::try_from(value)?;
307             }
308         }
309         Ok(result)
310     }
311 }
312 
313 /// ResultSet of Asset with a c representation.
314 #[repr(C)]
315 pub struct AssetResultSet {
316     count: u32,
317     results: *mut AssetResult,
318 }
319 
320 impl TryFrom<&Vec<AssetMap>> for AssetResultSet {
321     type Error = AssetError;
322 
try_from(maps: &Vec<AssetMap>) -> Result<Self, Self::Error>323     fn try_from(maps: &Vec<AssetMap>) -> Result<Self, Self::Error> {
324         let mut result_set = AssetResultSet { count: maps.len() as u32, results: std::ptr::null_mut() };
325         result_set.results =
326             unsafe { AssetMalloc(result_set.count.wrapping_mul(size_of::<AssetResult>() as u32)) as *mut AssetResult };
327         if result_set.results.is_null() {
328             return log_throw_error!(
329                 ErrCode::OutOfMemory,
330                 "[FATAL][RUST SDK]Unable to allocate memory for Asset_ResultSet."
331             );
332         }
333         for (i, map) in maps.iter().enumerate() {
334             unsafe {
335                 let result = result_set.results.add(i);
336                 *result = AssetResult::try_from(map)?;
337             }
338         }
339         Ok(result_set)
340     }
341 }
342