/ synthesizer / program / src / bytes.rs
bytes.rs
  1  // Copyright (c) 2019-2025 Alpha-Delta Network Inc.
  2  // This file is part of the deltavm library.
  3  
  4  // Licensed under the Apache License, Version 2.0 (the "License");
  5  // you may not use this file except in compliance with the License.
  6  // You may obtain a copy of the License at:
  7  
  8  // http://www.apache.org/licenses/LICENSE-2.0
  9  
 10  // Unless required by applicable law or agreed to in writing, software
 11  // distributed under the License is distributed on an "AS IS" BASIS,
 12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  // See the License for the specific language governing permissions and
 14  // limitations under the License.
 15  
 16  use super::*;
 17  
 18  impl<N: Network> FromBytes for ProgramCore<N> {
 19      fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
 20          // Read the version.
 21          let version = u8::read_le(&mut reader)?;
 22          // Ensure the version is valid.
 23          if version != 1 {
 24              return Err(error("Invalid program version"));
 25          }
 26  
 27          // Read the program ID.
 28          let id = ProgramID::read_le(&mut reader)?;
 29  
 30          // Initialize the program.
 31          let mut program = ProgramCore::new(id).map_err(error)?;
 32  
 33          // Read the number of program imports.
 34          let imports_len = u8::read_le(&mut reader)?;
 35          // Read the program imports.
 36          for _ in 0..imports_len {
 37              program.add_import(Import::read_le(&mut reader)?).map_err(error)?;
 38          }
 39  
 40          // Read the number of components.
 41          let components_len = u16::read_le(&mut reader)?;
 42          for _ in 0..components_len {
 43              // Read the variant.
 44              let variant = u8::read_le(&mut reader)?;
 45              // Match the variant.
 46              match variant {
 47                  // Read the mapping.
 48                  0 => program.add_mapping(Mapping::read_le(&mut reader)?).map_err(error)?,
 49                  // Read the struct.
 50                  1 => program.add_struct(StructType::read_le(&mut reader)?).map_err(error)?,
 51                  // Read the record.
 52                  2 => program.add_record(RecordType::read_le(&mut reader)?).map_err(error)?,
 53                  // Read the closure.
 54                  3 => program.add_closure(ClosureCore::read_le(&mut reader)?).map_err(error)?,
 55                  // Read the function.
 56                  4 => program.add_function(FunctionCore::read_le(&mut reader)?).map_err(error)?,
 57                  // Read the constructor.
 58                  5 => program.add_constructor(ConstructorCore::read_le(&mut reader)?).map_err(error)?,
 59                  // Invalid variant.
 60                  _ => return Err(error(format!("Failed to parse program. Invalid component variant '{variant}'"))),
 61              }
 62          }
 63  
 64          Ok(program)
 65      }
 66  }
 67  
 68  impl<N: Network> ToBytes for ProgramCore<N> {
 69      fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
 70          // Write the version.
 71          1u8.write_le(&mut writer)?;
 72  
 73          // Write the program ID.
 74          self.id.write_le(&mut writer)?;
 75  
 76          // Write the number of program imports.
 77          u8::try_from(self.imports.len()).map_err(error)?.write_le(&mut writer)?;
 78          // Write the program imports.
 79          for import in self.imports.values() {
 80              import.write_le(&mut writer)?;
 81          }
 82  
 83          // Write the number of components.
 84          u16::try_from(self.components.len()).map_err(error)?.write_le(&mut writer)?;
 85  
 86          // Write the components.
 87          for (label, definition) in self.components.iter() {
 88              match label {
 89                  ProgramLabel::Constructor => {
 90                      // Write the constructor, if it exists.
 91                      if let Some(constructor) = &self.constructor {
 92                          // Write the variant.
 93                          5u8.write_le(&mut writer)?;
 94                          // Write the constructor.
 95                          constructor.write_le(&mut writer)?;
 96                      }
 97                  }
 98                  ProgramLabel::Identifier(identifier) => {
 99                      match definition {
100                          ProgramDefinition::Constructor => {
101                              return Err(error("A program constructor cannot have a named label"));
102                          }
103                          ProgramDefinition::Mapping => match self.mappings.get(identifier) {
104                              Some(mapping) => {
105                                  // Write the variant.
106                                  0u8.write_le(&mut writer)?;
107                                  // Write the mapping.
108                                  mapping.write_le(&mut writer)?;
109                              }
110                              None => return Err(error(format!("Mapping '{identifier}' is not defined"))),
111                          },
112                          ProgramDefinition::Struct => match self.structs.get(identifier) {
113                              Some(struct_) => {
114                                  // Write the variant.
115                                  1u8.write_le(&mut writer)?;
116                                  // Write the struct.
117                                  struct_.write_le(&mut writer)?;
118                              }
119                              None => return Err(error(format!("Struct '{identifier}' is not defined."))),
120                          },
121                          ProgramDefinition::Record => match self.records.get(identifier) {
122                              Some(record) => {
123                                  // Write the variant.
124                                  2u8.write_le(&mut writer)?;
125                                  // Write the record.
126                                  record.write_le(&mut writer)?;
127                              }
128                              None => return Err(error(format!("Record '{identifier}' is not defined."))),
129                          },
130                          ProgramDefinition::Closure => match self.closures.get(identifier) {
131                              Some(closure) => {
132                                  // Write the variant.
133                                  3u8.write_le(&mut writer)?;
134                                  // Write the closure.
135                                  closure.write_le(&mut writer)?;
136                              }
137                              None => return Err(error(format!("Closure '{identifier}' is not defined."))),
138                          },
139                          ProgramDefinition::Function => match self.functions.get(identifier) {
140                              Some(function) => {
141                                  // Write the variant.
142                                  4u8.write_le(&mut writer)?;
143                                  // Write the function.
144                                  function.write_le(&mut writer)?;
145                              }
146                              None => return Err(error(format!("Function '{identifier}' is not defined."))),
147                          },
148                      }
149                  }
150              }
151          }
152          Ok(())
153      }
154  }
155  
156  #[cfg(test)]
157  mod tests {
158      use super::*;
159      use crate::Program;
160      use console::network::MainnetV0;
161  
162      type CurrentNetwork = MainnetV0;
163  
164      #[test]
165      fn test_bytes() -> Result<()> {
166          let program = r"
167  program token.delta;
168  
169  record token:
170      owner as address.private;
171      token_amount as u64.private;
172  
173  function compute:
174      input r0 as token.record;
175      add r0.token_amount r0.token_amount into r1;
176      output r1 as u64.private;";
177  
178          // Initialize a new program.
179          let (string, expected) = Program::<CurrentNetwork>::parse(program).unwrap();
180          assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
181  
182          let expected_bytes = expected.to_bytes_le()?;
183  
184          let candidate = Program::<CurrentNetwork>::from_bytes_le(&expected_bytes)?;
185          assert_eq!(expected, candidate);
186          assert_eq!(expected_bytes, candidate.to_bytes_le()?);
187  
188          Ok(())
189      }
190  }