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