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