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