bitoku_sdk_agent_native/
state.rs

1use borsh::{BorshDeserialize, BorshSerialize};
2use solana_program::{
3    msg,
4    program_error::ProgramError,
5    program_pack::{Pack, Sealed},
6    pubkey::Pubkey,
7};
8
9use crate::instruction::{unpack_request, Request};
10
11#[repr(C)]
12#[derive(Clone, BorshSerialize, BorshDeserialize, Debug)]
13pub struct BookKeeper {
14    pub status: [u8; 32],
15    pub next_id: u8,
16}
17
18#[repr(C)]
19#[derive(Clone, BorshSerialize, BorshDeserialize, Debug)]
20pub struct RequestData {
21    pub client_id: u8,
22    pub requester: Pubkey,
23    pub request: Request,
24}
25
26impl Sealed for BookKeeper {}
27
28impl Pack for BookKeeper {
29    const LEN: usize = 33;
30
31    fn unpack_from_slice(src: &[u8]) -> Result<Self, ProgramError> {
32        if src.len() < 33 {
33            return Err(ProgramError::InvalidAccountData);
34        }
35
36        let status: [u8; 32] = src[..32].try_into().unwrap();
37        let next_id = u8::from_le_bytes(src[32..33].try_into().unwrap())
38            .try_into()
39            .unwrap();
40
41        Ok(Self { status, next_id })
42    }
43
44    fn pack_into_slice(&self, dst: &mut [u8]) {
45        let status = self.status;
46        let next_id = self.next_id.to_le_bytes();
47
48        for i in 0..32 {
49            dst[i] = status[i];
50        }
51
52        for i in 32..33 {
53            dst[i] = next_id[0];
54        }
55    }
56}
57
58impl Sealed for RequestData {}
59
60impl Pack for RequestData {
61    const LEN: usize = 163;
62
63    fn unpack_from_slice(src: &[u8]) -> Result<Self, ProgramError> {
64        if src.len() < 163 {
65            return Err(ProgramError::InvalidAccountData);
66        }
67
68        let client_id = u8::from_le_bytes(src[..1].try_into().unwrap())
69            .try_into()
70            .unwrap();
71        let requester = Pubkey::new(&src[1..33]);
72        let request_bytes = &src[33..];
73
74        let request = unpack_request(request_bytes)?;
75
76        Ok(Self {
77            client_id,
78            requester,
79            request,
80        })
81    }
82
83    fn pack_into_slice(&self, dst: &mut [u8]) {
84        let client_id = self.client_id.to_le_bytes();
85        let requester = self.requester.to_bytes();
86
87        dst[0] = client_id[0];
88
89        for i in 1..33 {
90            dst[i] = requester[i - 1]
91        }
92
93        match &self.request {
94            Request::CreateBucket { name } => {
95                dst[33] = 0;
96                for i in 34..162 {
97                    dst[i] = name[i - 34];
98                }
99            }
100            Request::CreateFile { name } => {
101                dst[33] = 1;
102                for i in 34..162 {
103                    dst[i] = name[i - 34];
104                }
105            }
106            Request::WriteFile { name, file_id } => {
107                dst[33] = 2;
108                for i in 34..162 {
109                    dst[i] = name[i - 34];
110                }
111                dst[162] = *file_id;
112            }
113            Request::CloseFile { name, file_id } => {
114                dst[33] = 3;
115                for i in 34..162 {
116                    dst[i] = name[i - 34];
117                }
118                dst[162] = *file_id;
119            }
120            Request::DeleteFile { name, file_id } => {
121                dst[33] = 4;
122                for i in 34..162 {
123                    dst[i] = name[i - 34];
124                }
125                dst[162] = *file_id;
126            }
127            Request::SetPosition { name, file_id } => {
128                dst[33] = 5;
129                for i in 34..162 {
130                    dst[i] = name[i - 34];
131                }
132                dst[162] = *file_id;
133            }
134            Request::OpenFile { name, file_id } => {
135                dst[33] = 6;
136                for i in 34..162 {
137                    dst[i] = name[i - 34];
138                }
139                dst[162] = *file_id;
140            }
141            Request::ReadFile { name, file_id } => {
142                dst[33] = 7;
143                for i in 34..162 {
144                    dst[i] = name[i - 34];
145                }
146                dst[162] = *file_id;
147            }
148        }
149    }
150}
151
152pub fn addel(src: &mut [u8; 32], element: u8) {
153    let byte_index = element / 8;
154    let bit_offset = element % 8;
155    src[byte_index as usize] |= 1 << bit_offset;
156}
157
158pub fn isel(src: [u8; 32], element: u8) -> bool {
159    let byte_index = element / 8;
160    let bit_offset = element % 8;
161    let value = (src[byte_index as usize] >> bit_offset) & 1;
162
163    if value == 1 {
164        return true;
165    }
166    false
167}
168
169pub fn delel(src: &mut [u8; 32], element: u8) {
170    let byte_index = element / 8;
171    let bit_offset = element % 8;
172    src[byte_index as usize] &= !(1 << bit_offset);
173}
174
175pub fn validate_name(name: &[u8]) -> bool {
176    if name.len() > 128 as usize {
177        return false;
178    }
179
180    let non_zero_bytes: Vec<u8> = name.iter().take_while(|&b| *b != 0).copied().collect();
181
182    for b in non_zero_bytes {
183        if !(b >= b'a' && b <= b'z')
184            && !(b >= b'A' && b <= b'Z')
185            && !(b >= b'0' && b <= b'9')
186            && !(b == b'.' || b == b'/' || b == b'_' || b == b'+' || b == b'-')
187        {
188            return false;
189        }
190    }
191
192    true
193}
194
195#[cfg(test)]
196mod test {
197
198    use super::*;
199    use super::{Request, RequestData};
200    #[test]
201    fn test_pack() {
202        let mut name: [u8; 128] = [0; 128];
203        let bytes = "test".as_bytes();
204        name[..bytes.len()].copy_from_slice(bytes);
205
206        let requester = Pubkey::new_unique();
207        print!("name {:?}", String::from_utf8(name.to_vec()).unwrap());
208        let src = RequestData {
209            client_id: 85,
210            requester: requester,
211            request: Request::CloseFile { name, file_id: 69 },
212        };
213        let mut dst = [0u8; 163];
214        println!("{:?}", src);
215
216        let res = RequestData::pack(src, &mut dst);
217        print!("packed {:?}", res.unwrap());
218    }
219    #[test]
220    fn test_name_validation() {
221        let name = "test".as_bytes();
222
223        let bool = validate_name(&name);
224
225        assert!(bool);
226    }
227}