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