jam_program_blob/
program_blob.rs1use alloc::{borrow::Cow, string::String, vec::Vec};
2use scale::{Compact, Decode, Encode};
3
4#[derive(Clone, PartialEq, Eq, Encode, Decode)]
6pub struct CrateInfo {
7 pub name: String,
8 pub version: String,
9 pub license: String,
10 pub authors: Vec<String>,
11}
12
13#[derive(Clone, PartialEq, Eq, Encode, Decode)]
15pub enum ConventionalMetadata {
16 Info(CrateInfo),
17}
18
19pub struct ProgramBlob<'a> {
21 pub metadata: Cow<'a, [u8]>,
22 pub ro_data: Cow<'a, [u8]>,
23 pub rw_data: Cow<'a, [u8]>,
24 pub code_blob: Cow<'a, [u8]>,
25 pub rw_data_padding_pages: u16,
26 pub stack_size: u32,
27}
28
29fn read_u24(bytes: &mut &[u8]) -> Option<u32> {
30 let xs = bytes.get(..3)?;
31 *bytes = &bytes[3..];
32 Some(u32::from_le_bytes([xs[0], xs[1], xs[2], 0]))
33}
34
35fn write_u24(value: u32, output: &mut Vec<u8>) -> Result<(), ()> {
36 if value >= (1 << 24) {
37 return Err(());
38 }
39
40 output.extend_from_slice(&value.to_le_bytes()[0..3]);
41 Ok(())
42}
43
44#[test]
45fn read_write_u24() {
46 let mut output = Vec::new();
47 write_u24(0x00345678, &mut output).unwrap();
48 assert_eq!(read_u24(&mut &output[..]), Some(0x00345678));
49
50 assert!(write_u24(0x00ffffff, &mut output).is_ok());
51 assert!(write_u24(0x01000000, &mut output).is_err());
52}
53
54fn read_u16(bytes: &mut &[u8]) -> Option<u16> {
55 let xs = bytes.get(..2)?;
56 *bytes = &bytes[2..];
57 Some(u16::from_le_bytes([xs[0], xs[1]]))
58}
59
60fn read_u32(bytes: &mut &[u8]) -> Option<u32> {
61 let xs = bytes.get(..4)?;
62 *bytes = &bytes[4..];
63 Some(u32::from_le_bytes([xs[0], xs[1], xs[2], xs[3]]))
64}
65
66fn read_var(bytes: &mut &[u8]) -> Option<u32> {
67 Some(Compact::<u32>::decode(bytes).ok()?.0)
68}
69
70fn write_var(value: u32, output: &mut Vec<u8>) {
71 Compact::<u32>(value).encode_to(output)
72}
73
74#[test]
75fn read_write_var() {
76 let mut output = Vec::new();
77 let vals = [0x00345678, 0x00, 0x01, 0x7f, 0x80, 0xffffffff];
78 for i in vals.into_iter() {
79 write_var(i, &mut output);
80 }
81 let mut cursor = output.as_ref();
82 for i in vals.into_iter() {
83 assert_eq!(read_var(&mut cursor), Some(i));
84 }
85}
86
87fn read_cow<'a>(bytes: &mut &'a [u8], length: u32) -> Option<Cow<'a, [u8]>> {
88 let length = length as usize;
89 let cow = bytes.get(..length)?;
90 *bytes = &bytes[length..];
91 Some(Cow::Borrowed(cow))
92}
93
94impl<'a> ProgramBlob<'a> {
95 pub fn from_bytes(mut bytes: &'a [u8]) -> Option<Self> {
96 let offset = read_var(&mut bytes)?;
97 let metadata = read_cow(&mut bytes, offset)?;
98 let ro_data_len = read_u24(&mut bytes)?;
99 let rw_data_len = read_u24(&mut bytes)?;
100 let rw_data_padding_pages = read_u16(&mut bytes)?;
101 let stack_size = read_u24(&mut bytes)?;
102 let ro_data = read_cow(&mut bytes, ro_data_len)?;
103 let rw_data = read_cow(&mut bytes, rw_data_len)?;
104 let code_blob_len = read_u32(&mut bytes)?;
105 let code_blob = read_cow(&mut bytes, code_blob_len)?;
106
107 if !bytes.is_empty() {
108 return None;
109 }
110
111 Some(ProgramBlob {
112 metadata,
113 rw_data_padding_pages,
114 stack_size,
115 ro_data,
116 rw_data,
117 code_blob,
118 })
119 }
120
121 pub fn to_vec(&self) -> Result<Vec<u8>, &'static str> {
122 let mut output = Vec::new();
123 write_var(
124 u32::try_from(self.metadata.len()).map_err(|_| "metadata too large")?,
125 &mut output,
126 );
127 output.extend_from_slice(&self.metadata);
128 write_u24(u32::try_from(self.ro_data.len()).map_err(|_| "too large RO data")?, &mut output)
129 .map_err(|_| "too large RO data")?;
130 write_u24(u32::try_from(self.rw_data.len()).map_err(|_| "too large RW data")?, &mut output)
131 .map_err(|_| "too large RW data")?;
132 output.extend_from_slice(&self.rw_data_padding_pages.to_le_bytes());
133 write_u24(self.stack_size, &mut output).map_err(|_| "too large stack size")?;
134 output.extend_from_slice(&self.ro_data);
135 output.extend_from_slice(&self.rw_data);
136 output.extend_from_slice(
137 &u32::try_from(self.code_blob.len()).map_err(|_| "too large code")?.to_le_bytes(),
138 );
139 output.extend_from_slice(&self.code_blob);
140 Ok(output)
141 }
142}