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