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