rs_zephyr_sdk/
database.rs

1use crate::{env::EnvClient, external::{env_push_stack, read_raw, update_raw, write_raw}, symbol, to_fixed, SdkError};
2use serde::{Deserialize, Serialize};
3
4#[derive(Clone, Deserialize, Serialize)]
5pub struct TypeWrap(pub Vec<u8>);
6
7impl TypeWrap {
8    pub fn to_i128(&self) -> i128 {
9        let bytes = to_fixed::<u8, 16>(self.0.clone());
10        i128::from_be_bytes(bytes)
11    }
12
13    pub fn to_u64(&self) -> u64 {
14        let bytes = to_fixed::<u8, 8>(self.0.clone());
15        u64::from_be_bytes(bytes)
16    }
17}
18
19/// Object returned by database reads.
20/// It's a wrapper for table rows.
21#[derive(Clone, Deserialize, Serialize)]
22pub struct TableRows {
23    /// Rows within the table
24    pub rows: Vec<TableRow>,
25}
26
27/// Condition clauses that can be applied when reading the
28/// database.
29pub enum Condition {
30    /// A given column is equal to a certain object.
31    ColumnEqualTo(String, Vec<u8>)
32}
33
34/// Wraps a single row.
35#[derive(Clone, Deserialize, Serialize)]
36pub struct TableRow {
37    /// Vector of wrapped columns.
38    pub row: Vec<TypeWrap>,
39}
40
41mod unsafe_helpers {
42    use crate::external::env_push_stack;
43
44    pub(crate) unsafe fn push_head(table_name: i64, columns: Vec<i64>) {
45        env_push_stack(table_name as i64);
46        env_push_stack(columns.len() as i64);
47
48        for col in columns {
49            env_push_stack(col)
50        }
51    }
52
53    pub(crate) unsafe fn push_data_segments(segments: Vec<(i64, i64)>) {
54        env_push_stack(segments.len() as i64);
55
56        for segment in segments {
57            env_push_stack(segment.0);
58            env_push_stack(segment.1);
59        }
60    }
61}
62
63#[derive(Clone, Default)]
64pub struct Database {}
65
66impl Database {
67    pub fn read_table(table_name: &str, columns: &[&str]) -> Result<TableRows, SdkError> {
68        let table_name = symbol::Symbol::try_from_bytes(table_name.as_bytes()).unwrap();
69        let cols = columns
70            .into_iter()
71            .map(|col| symbol::Symbol::try_from_bytes(col.as_bytes()).unwrap().0 as i64)
72            .collect::<Vec<i64>>();
73
74        unsafe {
75            unsafe_helpers::push_head(table_name.0 as i64, cols)
76        }
77        
78        let (status, offset, size) = unsafe { read_raw() };
79        SdkError::express_from_status(status)?;
80        
81        let table = {
82            let memory: *const u8 = offset as *const u8;
83
84            let slice = unsafe {
85                core::slice::from_raw_parts(memory, size as usize)
86            };
87
88            if let Ok(table) = bincode::deserialize::<TableRows>(slice) {
89                table
90            } else {
91                return Err(SdkError::Conversion)
92            }
93        };
94
95        Ok(table)
96
97    }
98
99    pub fn write_table(table_name: &str, columns: &[&str], segments: &[&[u8]]) -> Result<(), SdkError> {
100        let table_name = symbol::Symbol::try_from_bytes(table_name.as_bytes()).unwrap();
101        let cols = columns
102            .into_iter()
103            .map(|col| symbol::Symbol::try_from_bytes(col.as_bytes()).unwrap().0 as i64)
104            .collect::<Vec<i64>>();
105
106        let segments = segments
107            .into_iter()
108            .map(|segment| (segment.as_ptr() as i64, segment.len() as i64))
109            .collect::<Vec<(i64, i64)>>();
110
111        unsafe {
112            unsafe_helpers::push_head(table_name.0 as i64, cols);
113            unsafe_helpers::push_data_segments(segments);
114        }
115
116        let status = unsafe { write_raw() };
117        SdkError::express_from_status(status)
118    }
119
120    pub fn update_table(table_name: &str, columns: &[&str], segments: &[&[u8]], conditions: &[Condition]) -> Result<(), SdkError> {
121        let table_name = symbol::Symbol::try_from_bytes(table_name.as_bytes()).unwrap();
122        let cols = columns
123            .into_iter()
124            .map(|col| symbol::Symbol::try_from_bytes(col.as_bytes()).unwrap().0 as i64)
125            .collect::<Vec<i64>>();
126
127        let segments = segments
128            .into_iter()
129            .map(|segment| (segment.as_ptr() as i64, segment.len() as i64))
130            .collect::<Vec<(i64, i64)>>();
131
132        unsafe {
133            unsafe_helpers::push_head(table_name.0 as i64, cols);
134            unsafe_helpers::push_data_segments(segments);
135
136            env_push_stack(conditions.len() as i64);
137
138            let mut args = Vec::new();
139            for cond in conditions {
140                let (colname, operator, value) = match cond {
141                    Condition::ColumnEqualTo(colname, value) => (colname, 0, value)
142                };
143
144                env_push_stack(symbol::Symbol::try_from_bytes(colname.as_bytes()).unwrap().0 as i64);
145                env_push_stack(operator as i64);
146
147                args.push((value.as_ptr() as i64, value.len() as i64))
148            }
149
150            env_push_stack(args.len() as i64);
151
152            for segment in args {
153                env_push_stack(segment.0);
154                env_push_stack(segment.1);
155            }
156        }
157
158        let status = unsafe { update_raw() };
159        SdkError::express_from_status(status)
160    }
161}
162
163pub trait DatabaseInteract {
164    fn read_to_rows(env: &EnvClient) -> Vec<Self> where Self: Sized;
165
166    fn put(&self, env: &EnvClient);
167
168    fn update(&self, env: &EnvClient, conditions: &[Condition]);
169}