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