kerbalobjects/
common.rs

1use std::collections::hash_map::DefaultHasher;
2use std::hash::Hash;
3use std::hash::Hasher;
4
5use crate::{KOSValueParseError, OpcodeParseError};
6
7/// A struct to iterate over the bytes of a buffer, and keep track of the current position
8/// for better error messages
9#[derive(Debug, Clone)]
10pub struct BufferIterator<'a> {
11    index: usize,
12    source: &'a [u8],
13}
14
15impl<'a> BufferIterator<'a> {
16    /// Creates a new BufferIterator over a source buffer
17    pub fn new(source: &'a [u8]) -> Self {
18        Self { index: 0, source }
19    }
20
21    /// Peeks the next value in the buffer, if any.
22    ///
23    /// Returns Some(value) if there is one, or None if EOF has been reached.
24    pub fn peek(&self) -> Option<u8> {
25        self.source.get(self.index).copied()
26    }
27
28    /// Returns the current byte index into the file
29    pub fn current_index(&self) -> usize {
30        self.index
31    }
32
33    /// Copies the internal buffer to a new Vec<u8>.
34    pub fn collect_vec(self) -> Vec<u8> {
35        self.source.to_vec()
36    }
37
38    /// Returns the size of the source buffer
39    pub fn len(&self) -> usize {
40        self.source.len()
41    }
42
43    /// Returns true if this iterator is empty
44    pub fn is_empty(&self) -> bool {
45        self.current_index() == self.source.len()
46    }
47}
48
49impl Iterator for BufferIterator<'_> {
50    type Item = u8;
51
52    fn next(&mut self) -> Option<Self::Item> {
53        let b = self.source.get(self.index).copied()?;
54
55        // We only increment if we were successful
56        self.index += 1;
57
58        Some(b)
59    }
60
61    fn size_hint(&self) -> (usize, Option<usize>) {
62        (self.len(), Some(self.len()))
63    }
64}
65
66impl std::io::Read for BufferIterator<'_> {
67    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
68        self.source.read(buf)
69    }
70}
71
72/// Allows a type to allow a Kerbal Machine Code or Kerbal Object file to be written into it
73pub trait WritableBuffer {
74    /// Notifies this buffer that if it can, it should resize by the *additional* amount
75    /// specified
76    fn allocate_more(&mut self, amount: usize);
77    /// Writes a single byte to this buffer
78    fn write(&mut self, val: u8);
79    /// Writes a byte slice to this buffer
80    fn write_bytes(&mut self, val: &[u8]);
81}
82
83impl WritableBuffer for Vec<u8> {
84    fn allocate_more(&mut self, amount: usize) {
85        // If this panics, we are already screwed
86        self.try_reserve(amount).unwrap();
87    }
88
89    fn write(&mut self, val: u8) {
90        self.push(val);
91    }
92
93    fn write_bytes(&mut self, val: &[u8]) {
94        self.extend_from_slice(val);
95    }
96}
97
98/// Allows a type to be converted to bytes and appended to a WriteableBuffer
99pub trait ToBytes {
100    /// Converts a type into bytes and appends it to the buffer.
101    fn to_bytes(&self, buf: &mut impl WritableBuffer);
102}
103
104/// Allows a type to be converted from bytes from a BufferIterator to itself.
105pub trait FromBytes {
106    /// The error type returned when the conversion fails
107    type Error;
108    /// Parses a value from the buffer iterator.
109    fn from_bytes(source: &mut BufferIterator) -> Result<Self, Self::Error>
110    where
111        Self: Sized;
112}
113
114/// The type of an internal value within Kerbal Operating System.
115///
116/// See [KOSValue](crate::KOSValue) for what these values look like.
117///
118/// This enum just describes the "type" of the KOSValue, which is stored as a single
119/// byte that prefixes the value (if there is one), which allows kOS to know how to interpret
120/// the following bytes.
121///
122#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
123#[repr(u8)]
124pub enum KOSType {
125    /// A null value
126    Null = 0,
127    /// A raw boolean
128    Bool = 1,
129    /// A single (signed) byte
130    Byte = 2,
131    /// A signed 16-bit integer
132    Int16 = 3,
133    /// A signed 32-bit integer
134    Int32 = 4,
135    /// A 32-bit floating point number
136    Float = 5,
137    /// A 64-bit floating point number
138    Double = 6,
139    /// A raw string
140    String = 7,
141    /// An argument marker
142    ArgMarker = 8,
143    /// A signed 32-bit integer "value"
144    ScalarInt = 9,
145    /// A 64-bit floating point number "value"
146    ScalarDouble = 10,
147    /// A boolean "value"
148    BoolValue = 11,
149    /// A string "value"
150    StringValue = 12,
151}
152
153impl From<KOSType> for u8 {
154    fn from(t: KOSType) -> Self {
155        t as u8
156    }
157}
158
159impl TryFrom<u8> for KOSType {
160    type Error = ();
161
162    fn try_from(value: u8) -> Result<Self, Self::Error> {
163        match value {
164            0 => Ok(Self::Null),
165            1 => Ok(Self::Bool),
166            2 => Ok(Self::Byte),
167            3 => Ok(Self::Int16),
168            4 => Ok(Self::Int32),
169            5 => Ok(Self::Float),
170            6 => Ok(Self::Double),
171            7 => Ok(Self::String),
172            8 => Ok(Self::ArgMarker),
173            9 => Ok(Self::ScalarInt),
174            10 => Ok(Self::ScalarDouble),
175            11 => Ok(Self::BoolValue),
176            12 => Ok(Self::StringValue),
177            _ => Err(()),
178        }
179    }
180}
181
182impl ToBytes for KOSType {
183    fn to_bytes(&self, buf: &mut impl WritableBuffer) {
184        (*self as u8).to_bytes(buf);
185    }
186}
187
188impl FromBytes for KOSType {
189    type Error = ();
190
191    fn from_bytes(source: &mut BufferIterator) -> Result<Self, Self::Error>
192    where
193        Self: Sized,
194    {
195        Self::try_from(u8::from_bytes(source)?)
196    }
197}
198
199/// An internal value within Kerbal Operating System.
200///
201/// These are documented within the GitHub repo's [KSM Docs](https://github.com/newcomb-luke/kerbalobjects.rs/blob/main/docs/KSM-file-format.md#argument-section).
202/// These are used as operands to instructions and stored in the KO file's data section,
203/// and a KSM file's argument section.
204///
205/// Each value takes up 1 byte just for the "data type" so that kOS knows how to load the value.
206///
207/// The "Value" types (ScalarInt, ScalarDouble, BoolValue, StringValue) are different from their
208/// non-value counterparts in that the "Value" types have more built-in suffixes, and are the
209/// type used when there are any user-created values, as opposed to instruction operands. See
210/// KSM docs for more information.
211///
212#[derive(Debug, Clone)]
213pub enum KOSValue {
214    /// A null value, rarely used. Only takes up 1 byte.
215    Null,
216    /// A boolean. Takes up 2 bytes.
217    Bool(bool),
218    /// A signed byte. Takes up 2 bytes.
219    Byte(i8),
220    /// A signed 16-bit integer. Takes up 3 bytes.
221    Int16(i16),
222    /// A signed 32-bit integer. Takes up 5 bytes.
223    Int32(i32),
224    /// A 32-bit floating point number. Takes up 5 bytes.
225    Float(f32),
226    /// A 64-bit floating point number. Takes up 9 bytes.
227    Double(f64),
228    /// A string. Takes up 2 + length bytes.
229    String(String),
230    /// An argument marker. Takes up 1 byte.
231    ArgMarker,
232    /// A signed 32-bit integer. Takes up 5 bytes.
233    ScalarInt(i32),
234    /// A 64-bit floating point number. Takes up 9 bytes.
235    ScalarDouble(f64),
236    /// A boolean. Takes up 2 bytes.
237    BoolValue(bool),
238    /// A string. Takes up 2 + length bytes.
239    StringValue(String),
240}
241
242impl KOSValue {
243    /// Returns the size of the value in bytes.
244    pub fn size_bytes(&self) -> usize {
245        match &self {
246            Self::Null | Self::ArgMarker => 1,
247            Self::Bool(_) | Self::Byte(_) | Self::BoolValue(_) => 2,
248            Self::Int16(_) => 3,
249            Self::Int32(_) | Self::Float(_) | Self::ScalarInt(_) => 5,
250            Self::Double(_) | Self::ScalarDouble(_) => 9,
251            Self::String(s) | Self::StringValue(s) => {
252                2 + s.len() // 1 byte for the type, 1 byte for the length, and then the string
253            }
254        }
255    }
256}
257
258impl Hash for KOSValue {
259    fn hash<H: Hasher>(&self, state: &mut H) {
260        match self {
261            Self::Null => 0.hash(state),
262            Self::Bool(b) => {
263                1.hash(state);
264                b.hash(state);
265            }
266            Self::Byte(b) => {
267                2.hash(state);
268                b.hash(state);
269            }
270            Self::Int16(i) => {
271                3.hash(state);
272                i.hash(state);
273            }
274            Self::Int32(i) => {
275                4.hash(state);
276                i.hash(state);
277            }
278            Self::Float(f) => {
279                5.hash(state);
280                f.to_bits().hash(state);
281            }
282            Self::Double(d) => {
283                6.hash(state);
284                d.to_bits().hash(state);
285            }
286            Self::String(s) => {
287                7.hash(state);
288                s.hash(state);
289            }
290            Self::ArgMarker => {
291                8.hash(state);
292            }
293            Self::ScalarInt(i) => {
294                9.hash(state);
295                i.hash(state);
296            }
297            Self::ScalarDouble(d) => {
298                10.hash(state);
299                d.to_bits().hash(state);
300            }
301            Self::BoolValue(b) => {
302                11.hash(state);
303                b.hash(state);
304            }
305            Self::StringValue(s) => {
306                12.hash(state);
307                s.hash(state);
308            }
309        }
310    }
311}
312
313impl PartialEq for KOSValue {
314    fn eq(&self, other: &Self) -> bool {
315        let mut hasher_1 = DefaultHasher::new();
316        self.hash(&mut hasher_1);
317        let mut hasher_2 = DefaultHasher::new();
318        other.hash(&mut hasher_2);
319
320        hasher_1.finish() == hasher_2.finish()
321    }
322}
323
324impl Eq for KOSValue {}
325
326impl ToBytes for KOSValue {
327    fn to_bytes(&self, buf: &mut impl WritableBuffer) {
328        match self {
329            Self::Null => {
330                buf.write(0);
331            }
332            Self::Bool(b) => {
333                buf.write(1);
334                b.to_bytes(buf);
335            }
336            Self::Byte(b) => {
337                buf.write(2);
338                b.to_bytes(buf);
339            }
340            Self::Int16(i) => {
341                buf.write(3);
342                i.to_bytes(buf);
343            }
344            Self::Int32(i) => {
345                buf.write(4);
346                i.to_bytes(buf);
347            }
348            Self::Float(f) => {
349                buf.write(5);
350                f.to_bytes(buf);
351            }
352            Self::Double(f) => {
353                buf.write(6);
354                f.to_bytes(buf);
355            }
356            Self::String(s) => {
357                buf.write(7);
358                buf.write(s.len() as u8);
359                s.to_bytes(buf);
360            }
361            Self::ArgMarker => {
362                buf.write(8);
363            }
364            Self::ScalarInt(i) => {
365                buf.write(9);
366                i.to_bytes(buf);
367            }
368            Self::ScalarDouble(f) => {
369                buf.write(10);
370                f.to_bytes(buf);
371            }
372            Self::BoolValue(b) => {
373                buf.write(11);
374                b.to_bytes(buf);
375            }
376            Self::StringValue(s) => {
377                buf.write(12);
378                buf.write(s.len() as u8);
379                s.to_bytes(buf);
380            }
381        }
382    }
383}
384
385impl FromBytes for KOSValue {
386    type Error = KOSValueParseError;
387
388    fn from_bytes(source: &mut BufferIterator) -> Result<Self, Self::Error>
389    where
390        Self: Sized,
391    {
392        let raw_type = source.next().ok_or(KOSValueParseError::EOF)?;
393        let kos_type =
394            KOSType::try_from(raw_type).map_err(|_| KOSValueParseError::InvalidType(raw_type))?;
395
396        match kos_type {
397            KOSType::Null => Ok(KOSValue::Null),
398            KOSType::Bool => bool::from_bytes(source).map(KOSValue::Bool),
399            KOSType::Byte => i8::from_bytes(source).map(KOSValue::Byte),
400            KOSType::Int16 => i16::from_bytes(source).map(KOSValue::Int16),
401            KOSType::Int32 => i32::from_bytes(source).map(KOSValue::Int32),
402            KOSType::Float => f32::from_bytes(source).map(KOSValue::Float),
403            KOSType::Double => f64::from_bytes(source).map(KOSValue::Double),
404            KOSType::String => String::from_bytes(source).map(KOSValue::String),
405            KOSType::ArgMarker => Ok(KOSValue::ArgMarker),
406            KOSType::ScalarInt => i32::from_bytes(source).map(KOSValue::ScalarInt),
407            KOSType::ScalarDouble => f64::from_bytes(source).map(KOSValue::ScalarDouble),
408            KOSType::BoolValue => bool::from_bytes(source).map(KOSValue::BoolValue),
409            KOSType::StringValue => String::from_bytes(source).map(KOSValue::StringValue),
410        }
411        .map_err(|_| KOSValueParseError::EOF)
412    }
413}
414
415impl ToBytes for bool {
416    fn to_bytes(&self, buf: &mut impl WritableBuffer) {
417        buf.write(if *self { 1 } else { 0 });
418    }
419}
420
421impl ToBytes for u8 {
422    fn to_bytes(&self, buf: &mut impl WritableBuffer) {
423        buf.write(*self);
424    }
425}
426
427impl ToBytes for i8 {
428    fn to_bytes(&self, buf: &mut impl WritableBuffer) {
429        buf.write((*self) as u8);
430    }
431}
432
433impl ToBytes for u16 {
434    fn to_bytes(&self, buf: &mut impl WritableBuffer) {
435        buf.write_bytes(&self.to_le_bytes());
436    }
437}
438
439impl ToBytes for i16 {
440    fn to_bytes(&self, buf: &mut impl WritableBuffer) {
441        buf.write_bytes(&self.to_le_bytes());
442    }
443}
444
445impl ToBytes for u32 {
446    fn to_bytes(&self, buf: &mut impl WritableBuffer) {
447        buf.write_bytes(&self.to_le_bytes());
448    }
449}
450
451impl ToBytes for i32 {
452    fn to_bytes(&self, buf: &mut impl WritableBuffer) {
453        buf.write_bytes(&self.to_le_bytes());
454    }
455}
456
457impl ToBytes for f32 {
458    fn to_bytes(&self, buf: &mut impl WritableBuffer) {
459        buf.write_bytes(&self.to_le_bytes());
460    }
461}
462
463impl ToBytes for f64 {
464    fn to_bytes(&self, buf: &mut impl WritableBuffer) {
465        buf.write_bytes(&self.to_le_bytes());
466    }
467}
468
469impl ToBytes for &str {
470    fn to_bytes(&self, buf: &mut impl WritableBuffer) {
471        buf.write_bytes(self.as_bytes());
472    }
473}
474
475impl ToBytes for String {
476    fn to_bytes(&self, buf: &mut impl WritableBuffer) {
477        buf.write_bytes(self.as_bytes());
478    }
479}
480
481impl FromBytes for bool {
482    type Error = ();
483
484    fn from_bytes(source: &mut BufferIterator) -> Result<Self, Self::Error> {
485        source.next().map(|x| x != 0).ok_or(())
486    }
487}
488
489impl FromBytes for u8 {
490    type Error = ();
491
492    fn from_bytes(source: &mut BufferIterator) -> Result<Self, Self::Error> {
493        source.next().ok_or(())
494    }
495}
496
497impl FromBytes for i8 {
498    type Error = ();
499
500    fn from_bytes(source: &mut BufferIterator) -> Result<Self, Self::Error> {
501        source.next().map(|x| x as i8).ok_or(())
502    }
503}
504
505impl FromBytes for u16 {
506    type Error = ();
507
508    fn from_bytes(source: &mut BufferIterator) -> Result<Self, Self::Error> {
509        let mut slice = [0u8; 2];
510        for b in &mut slice {
511            if let Some(byte) = source.next() {
512                *b = byte;
513            } else {
514                return Err(());
515            }
516        }
517        Ok(u16::from_le_bytes(slice))
518    }
519}
520
521impl FromBytes for i16 {
522    type Error = ();
523
524    fn from_bytes(source: &mut BufferIterator) -> Result<Self, Self::Error> {
525        let mut slice = [0u8; 2];
526        for b in &mut slice {
527            if let Some(byte) = source.next() {
528                *b = byte;
529            } else {
530                return Err(());
531            }
532        }
533        Ok(i16::from_le_bytes(slice))
534    }
535}
536
537impl FromBytes for u32 {
538    type Error = ();
539
540    fn from_bytes(source: &mut BufferIterator) -> Result<Self, Self::Error> {
541        let mut slice = [0u8; 4];
542        for b in &mut slice {
543            if let Some(byte) = source.next() {
544                *b = byte;
545            } else {
546                return Err(());
547            }
548        }
549        Ok(u32::from_le_bytes(slice))
550    }
551}
552
553impl FromBytes for i32 {
554    type Error = ();
555
556    fn from_bytes(source: &mut BufferIterator) -> Result<Self, Self::Error> {
557        let mut slice = [0u8; 4];
558        for b in &mut slice {
559            if let Some(byte) = source.next() {
560                *b = byte;
561            } else {
562                return Err(());
563            }
564        }
565        Ok(i32::from_le_bytes(slice))
566    }
567}
568
569impl FromBytes for f32 {
570    type Error = ();
571
572    fn from_bytes(source: &mut BufferIterator) -> Result<Self, Self::Error> {
573        let mut slice = [0u8; 4];
574        for b in &mut slice {
575            if let Some(byte) = source.next() {
576                *b = byte;
577            } else {
578                return Err(());
579            }
580        }
581        Ok(f32::from_le_bytes(slice))
582    }
583}
584
585impl FromBytes for f64 {
586    type Error = ();
587
588    fn from_bytes(source: &mut BufferIterator) -> Result<Self, Self::Error> {
589        let mut slice = [0u8; 8];
590        for b in &mut slice {
591            if let Some(byte) = source.next() {
592                *b = byte;
593            } else {
594                return Err(());
595            }
596        }
597        Ok(f64::from_le_bytes(slice))
598    }
599}
600
601impl FromBytes for String {
602    type Error = ();
603
604    fn from_bytes(source: &mut BufferIterator) -> Result<Self, Self::Error> {
605        let len = source.next().ok_or(())? as usize;
606        let mut s = String::with_capacity(len);
607        for _ in 0..len {
608            if let Some(byte) = source.next() {
609                s.push(byte as char);
610            } else {
611                return Err(());
612            }
613        }
614        Ok(s)
615    }
616}
617
618/// The opcode of a kOS machine code instruction.
619///
620/// Each instruction is made up of an opcode, and a series of zero or more operands.
621/// This enum contains all currently supported kOS opcodes, and 2 additional ones.
622///
623/// Opcode::Bogus is the Opcode variant used to express that it is an unrecognized opcode.
624/// This is inspired by the actual kOS C# code.
625///
626/// Opcode::Pushv is an internal value that is can be used by tools working with kOS machine code,
627/// and it represents a normal Opcode::Push instruction, however specifying that the operand should be
628/// stored as a KOSValue "Value" type (ScalarDouble, StringValue). This is mostly just useful for the
629/// KASM assembler implementation.
630///
631/// See the [instruction docs](https://github.com/newcomb-luke/kerbalobjects.rs/blob/main/docs/Instruction-docs.md) for
632/// more detailed documentation.
633///
634#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
635pub enum Opcode {
636    /// Specified also in the kOS C# code, represents an unrecognized Opcode
637    Bogus,
638    /// Stop executing for this cycle.
639    Eof,
640    /// Aborts the current program and returns to the interpreter.
641    Eop,
642    /// No operation: does nothing.
643    Nop,
644    /// Consumes the top value of the stack and stores it in the variable named by the operand.
645    Sto,
646    /// Consumes the top value of the stack and unsets the variable that it names.
647    Uns,
648    /// Gets the suffix of a variable on the stack.
649    Gmb,
650    /// Sets the suffix of a variable on the stack.
651    Smb,
652    /// Gets the value of an index into a variable on the stack.
653    Gidx,
654    /// Sets the value of an index into a variable on the stack.
655    Sidx,
656    /// Branches to the provided location if the value on the stack is false.
657    Bfa,
658    /// Unconditionally branches to the provided location.
659    Jmp,
660    /// Adds two variables on the stack. Also used to concatenate strings.
661    Add,
662    /// Subtracts two variables on the stack.
663    Sub,
664    /// Multiplies two variables on the stack.
665    Mul,
666    /// Divides two variables on the stack.
667    Div,
668    /// Raises a value on the stack to another value on the stack.
669    Pow,
670    /// Compares two values on the stack. Pushes true if one is greater, false otherwise.
671    ///
672    /// See instruction docs for the order of values in the comparison.
673    Cgt,
674    /// Compares two values on the stack. Pushes true if one is less, false otherwise.
675    ///
676    /// See instruction docs for the order of values in the comparison.
677    Clt,
678    /// Compares two values on the stack. Pushes true if one is greater or equal, false otherwise.
679    ///
680    /// See instruction docs for the order of values in the comparison.
681    Cge,
682    /// Compares two values on the stack. Pushes true if one is less or equal, false otherwise.
683    ///
684    /// See instruction docs for the order of values in the comparison.
685    Cle,
686    /// Compares two values on the stack. Pushes true if both are equal, false otherwise.
687    Ceq,
688    /// Compares two values on the stack. Pushes true if both are not equal, false otherwise.
689    Cne,
690    /// Consumes a value on the stack, and pushes back the negative.
691    Neg,
692    /// Converts a value on the stack into a boolean.
693    ///
694    /// See instruction docs for how the conversion is performed.
695    Bool,
696    /// Converts a value on the stack into a boolean, and pushes the negated value.
697    ///
698    /// See instruction docs for how the conversion is performed.
699    Not,
700    /// Performs the logical AND operation between boolean values.
701    And,
702    /// Performs the logical OR operation between boolean values.
703    Or,
704    /// Calls a function.
705    ///
706    /// See instruction docs for call instruction format.
707    Call,
708    /// Returns from a function call.
709    Ret,
710    /// Pushes a value to the stack.
711    Push,
712    /// Pops a value off of the stack and discards it.
713    Pop,
714    /// Duplicates the value on the top of the stack.
715    Dup,
716    /// Swaps the top value of the stack with the value just below.
717    Swap,
718    /// "Evaluates" the top value of the stack. Usually this replaces a variable name with
719    /// the variable's value.
720    Eval,
721    /// Adds a new kOS trigger.
722    Addt,
723    /// Removes a kOS trigger.
724    Rmvt,
725    /// Waits for a specified amount of time.
726    Wait,
727    /// Gets the suffixed method of a variable on the stack.
728    Gmet,
729    /// Consumes the top value of the stack and stores it in the variable named by the operand.
730    /// If the variable of the provided name does not exist, a new local variable is created.
731    Stol,
732    /// Consumes the top value of the stack and stores it in the variable named by the operand.
733    /// If the variable of the provided name does not exist, a new global variable is created.
734    Stog,
735    /// Begins a new variable scope
736    Bscp,
737    /// Ends a scope named by the provided id.
738    Escp,
739    /// Consumes the top value of the stack and stores it in the variable named by the operand.
740    /// If the variable of the provided name does not exist, an error occurs.
741    Stoe,
742    /// Pushes a function delegate to the stack.
743    Phdl,
744    /// Branches to the provided location if the value on the stack is true.
745    Btr,
746    /// Checks if the provided variable name exists.
747    Exst,
748    /// Asserts that the top of the stack is a KOSValue::ArgMarker
749    Argb,
750    /// Pushes true if the top of the stack is a KOSValue::ArgMarker, false if not.
751    Targ,
752    /// Tests if the current trigger is requested to be cancelled. Pushes true if it is, false if not.
753    Tcan,
754    /// Pushes a value that is replaced with the correct value after the file is loaded.
755    Prl,
756    /// Pushes a function delegate that is replaced with the correct value after the file is loaded.
757    Pdrl,
758    /// Resets the current internal kOS label value.
759    Lbrt,
760
761    /// An internal value created for use by the Kerbal Assembler. This is not an opcode recognized
762    /// by kOS, and should always be replaced with a regular Opcode::Push. This exists to be a
763    /// special instruction that pushes the "Value" version of an argument.
764    Pushv,
765}
766
767impl Opcode {
768    /// Returns the number of operands that this instruction type should have.
769    pub fn num_operands(&self) -> usize {
770        match self {
771            Opcode::Eof => 0,
772            Opcode::Eop => 0,
773            Opcode::Nop => 0,
774            Opcode::Sto => 1,
775            Opcode::Uns => 0,
776            Opcode::Gmb => 1,
777            Opcode::Smb => 1,
778            Opcode::Gidx => 0,
779            Opcode::Sidx => 0,
780            Opcode::Bfa => 1,
781            Opcode::Jmp => 1,
782            Opcode::Add => 0,
783            Opcode::Sub => 0,
784            Opcode::Mul => 0,
785            Opcode::Div => 0,
786            Opcode::Pow => 0,
787            Opcode::Cgt => 0,
788            Opcode::Clt => 0,
789            Opcode::Cge => 0,
790            Opcode::Cle => 0,
791            Opcode::Ceq => 0,
792            Opcode::Cne => 0,
793            Opcode::Neg => 0,
794            Opcode::Bool => 0,
795            Opcode::Not => 0,
796            Opcode::And => 0,
797            Opcode::Or => 0,
798            Opcode::Call => 2,
799            Opcode::Ret => 1,
800            Opcode::Push => 1,
801            Opcode::Pop => 0,
802            Opcode::Dup => 0,
803            Opcode::Swap => 0,
804            Opcode::Eval => 0,
805            Opcode::Addt => 2,
806            Opcode::Rmvt => 0,
807            Opcode::Wait => 0,
808            Opcode::Gmet => 1,
809            Opcode::Stol => 1,
810            Opcode::Stog => 1,
811            Opcode::Bscp => 2,
812            Opcode::Escp => 1,
813            Opcode::Stoe => 1,
814            Opcode::Phdl => 2,
815            Opcode::Btr => 1,
816            Opcode::Exst => 0,
817            Opcode::Argb => 0,
818            Opcode::Targ => 0,
819            Opcode::Tcan => 0,
820
821            Opcode::Prl => 1,
822            Opcode::Pdrl => 2,
823            Opcode::Lbrt => 1,
824
825            Opcode::Pushv => 1,
826
827            Opcode::Bogus => 0,
828        }
829    }
830}
831
832impl From<u8> for Opcode {
833    fn from(byte: u8) -> Self {
834        match byte {
835            0x31 => Opcode::Eof,
836            0x32 => Opcode::Eop,
837            0x33 => Opcode::Nop,
838            0x34 => Opcode::Sto,
839            0x35 => Opcode::Uns,
840            0x36 => Opcode::Gmb,
841            0x37 => Opcode::Smb,
842            0x38 => Opcode::Gidx,
843            0x39 => Opcode::Sidx,
844            0x3a => Opcode::Bfa,
845            0x3b => Opcode::Jmp,
846            0x3c => Opcode::Add,
847            0x3d => Opcode::Sub,
848            0x3e => Opcode::Mul,
849            0x3f => Opcode::Div,
850            0x40 => Opcode::Pow,
851            0x41 => Opcode::Cgt,
852            0x42 => Opcode::Clt,
853            0x43 => Opcode::Cge,
854            0x44 => Opcode::Cle,
855            0x45 => Opcode::Ceq,
856            0x46 => Opcode::Cne,
857            0x47 => Opcode::Neg,
858            0x48 => Opcode::Bool,
859            0x49 => Opcode::Not,
860            0x4a => Opcode::And,
861            0x4b => Opcode::Or,
862            0x4c => Opcode::Call,
863            0x4d => Opcode::Ret,
864            0x4e => Opcode::Push,
865            0x4f => Opcode::Pop,
866            0x50 => Opcode::Dup,
867            0x51 => Opcode::Swap,
868            0x52 => Opcode::Eval,
869            0x53 => Opcode::Addt,
870            0x54 => Opcode::Rmvt,
871            0x55 => Opcode::Wait,
872            0x57 => Opcode::Gmet,
873            0x58 => Opcode::Stol,
874            0x59 => Opcode::Stog,
875            0x5a => Opcode::Bscp,
876            0x5b => Opcode::Escp,
877            0x5c => Opcode::Stoe,
878            0x5d => Opcode::Phdl,
879            0x5e => Opcode::Btr,
880            0x5f => Opcode::Exst,
881            0x60 => Opcode::Argb,
882            0x61 => Opcode::Targ,
883            0x62 => Opcode::Tcan,
884
885            0xce => Opcode::Prl,
886            0xcd => Opcode::Pdrl,
887            0xf0 => Opcode::Lbrt,
888
889            0xfa => Opcode::Pushv,
890
891            _ => Opcode::Bogus,
892        }
893    }
894}
895
896impl From<Opcode> for u8 {
897    fn from(opcode: Opcode) -> Self {
898        match opcode {
899            Opcode::Bogus => 0x00,
900            Opcode::Eof => 0x31,
901            Opcode::Eop => 0x32,
902            Opcode::Nop => 0x33,
903            Opcode::Sto => 0x34,
904            Opcode::Uns => 0x35,
905            Opcode::Gmb => 0x36,
906            Opcode::Smb => 0x37,
907            Opcode::Gidx => 0x38,
908            Opcode::Sidx => 0x39,
909            Opcode::Bfa => 0x3a,
910            Opcode::Jmp => 0x3b,
911            Opcode::Add => 0x3c,
912            Opcode::Sub => 0x3d,
913            Opcode::Mul => 0x3e,
914            Opcode::Div => 0x3f,
915            Opcode::Pow => 0x40,
916            Opcode::Cgt => 0x41,
917            Opcode::Clt => 0x42,
918            Opcode::Cge => 0x43,
919            Opcode::Cle => 0x44,
920            Opcode::Ceq => 0x45,
921            Opcode::Cne => 0x46,
922            Opcode::Neg => 0x47,
923            Opcode::Bool => 0x48,
924            Opcode::Not => 0x49,
925            Opcode::And => 0x4a,
926            Opcode::Or => 0x4b,
927            Opcode::Call => 0x4c,
928            Opcode::Ret => 0x4d,
929            Opcode::Push => 0x4e,
930            Opcode::Pop => 0x4f,
931            Opcode::Dup => 0x50,
932            Opcode::Swap => 0x51,
933            Opcode::Eval => 0x52,
934            Opcode::Addt => 0x53,
935            Opcode::Rmvt => 0x54,
936            Opcode::Wait => 0x55,
937            Opcode::Gmet => 0x57,
938            Opcode::Stol => 0x58,
939            Opcode::Stog => 0x59,
940            Opcode::Bscp => 0x5a,
941            Opcode::Escp => 0x5b,
942            Opcode::Stoe => 0x5c,
943            Opcode::Phdl => 0x5d,
944            Opcode::Btr => 0x5e,
945            Opcode::Exst => 0x5f,
946            Opcode::Argb => 0x60,
947            Opcode::Targ => 0x61,
948            Opcode::Tcan => 0x62,
949
950            Opcode::Prl => 0xce,
951            Opcode::Pdrl => 0xcd,
952            Opcode::Lbrt => 0xf0,
953
954            Opcode::Pushv => 0xfa,
955        }
956    }
957}
958
959impl From<&str> for Opcode {
960    fn from(s: &str) -> Self {
961        match s {
962            "eof" => Opcode::Eof,
963            "eop" => Opcode::Eop,
964            "nop" => Opcode::Nop,
965            "sto" => Opcode::Sto,
966            "uns" => Opcode::Uns,
967            "gmb" => Opcode::Gmb,
968            "smb" => Opcode::Smb,
969            "gidx" => Opcode::Gidx,
970            "sidx" => Opcode::Sidx,
971            "bfa" => Opcode::Bfa,
972            "jmp" => Opcode::Jmp,
973            "add" => Opcode::Add,
974            "sub" => Opcode::Sub,
975            "mul" => Opcode::Mul,
976            "div" => Opcode::Div,
977            "pow" => Opcode::Pow,
978            "cgt" => Opcode::Cgt,
979            "clt" => Opcode::Clt,
980            "cge" => Opcode::Cge,
981            "cle" => Opcode::Cle,
982            "ceq" => Opcode::Ceq,
983            "cne" => Opcode::Cne,
984            "neg" => Opcode::Neg,
985            "bool" => Opcode::Bool,
986            "not" => Opcode::Not,
987            "and" => Opcode::And,
988            "or" => Opcode::Or,
989            "call" => Opcode::Call,
990            "ret" => Opcode::Ret,
991            "push" => Opcode::Push,
992            "pop" => Opcode::Pop,
993            "dup" => Opcode::Dup,
994            "swap" => Opcode::Swap,
995            "eval" => Opcode::Eval,
996            "addt" => Opcode::Addt,
997            "rmvt" => Opcode::Rmvt,
998            "wait" => Opcode::Wait,
999            "gmet" => Opcode::Gmet,
1000            "stol" => Opcode::Stol,
1001            "stog" => Opcode::Stog,
1002            "bscp" => Opcode::Bscp,
1003            "escp" => Opcode::Escp,
1004            "stoe" => Opcode::Stoe,
1005            "phdl" => Opcode::Phdl,
1006            "btr" => Opcode::Btr,
1007            "exst" => Opcode::Exst,
1008            "argb" => Opcode::Argb,
1009            "targ" => Opcode::Targ,
1010            "tcan" => Opcode::Tcan,
1011
1012            "prl" => Opcode::Prl,
1013            "pdrl" => Opcode::Pdrl,
1014            "lbrt" => Opcode::Lbrt,
1015
1016            "pushv" => Opcode::Pushv,
1017            &_ => Opcode::Bogus,
1018        }
1019    }
1020}
1021
1022impl From<Opcode> for &str {
1023    fn from(opcode: Opcode) -> Self {
1024        match opcode {
1025            Opcode::Eof => "eof",
1026            Opcode::Eop => "eop",
1027            Opcode::Nop => "nop",
1028            Opcode::Sto => "sto",
1029            Opcode::Uns => "uns",
1030            Opcode::Gmb => "gmb",
1031            Opcode::Smb => "smb",
1032            Opcode::Gidx => "gidx",
1033            Opcode::Sidx => "sidx",
1034            Opcode::Bfa => "bfa",
1035            Opcode::Jmp => "jmp",
1036            Opcode::Add => "add",
1037            Opcode::Sub => "sub",
1038            Opcode::Mul => "mul",
1039            Opcode::Div => "div",
1040            Opcode::Pow => "pow",
1041            Opcode::Cgt => "cgt",
1042            Opcode::Clt => "clt",
1043            Opcode::Cge => "cge",
1044            Opcode::Cle => "cle",
1045            Opcode::Ceq => "ceq",
1046            Opcode::Cne => "cne",
1047            Opcode::Neg => "neg",
1048            Opcode::Bool => "bool",
1049            Opcode::Not => "not",
1050            Opcode::And => "and",
1051            Opcode::Or => "or",
1052            Opcode::Call => "call",
1053            Opcode::Ret => "ret",
1054            Opcode::Push => "push",
1055            Opcode::Pop => "pop",
1056            Opcode::Dup => "dup",
1057            Opcode::Swap => "swap",
1058            Opcode::Eval => "eval",
1059            Opcode::Addt => "addt",
1060            Opcode::Rmvt => "rmvt",
1061            Opcode::Wait => "wait",
1062            Opcode::Gmet => "gmet",
1063            Opcode::Stol => "stol",
1064            Opcode::Stog => "stog",
1065            Opcode::Bscp => "bscp",
1066            Opcode::Escp => "escp",
1067            Opcode::Stoe => "stoe",
1068            Opcode::Phdl => "phdl",
1069            Opcode::Btr => "btr",
1070            Opcode::Exst => "exst",
1071            Opcode::Argb => "argb",
1072            Opcode::Targ => "targ",
1073            Opcode::Tcan => "tcan",
1074
1075            Opcode::Prl => "prl",
1076            Opcode::Pdrl => "pdrl",
1077            Opcode::Lbrt => "lbrt",
1078
1079            Opcode::Pushv => "pushv",
1080
1081            Opcode::Bogus => "bogus",
1082        }
1083    }
1084}
1085
1086impl ToBytes for Opcode {
1087    fn to_bytes(&self, buf: &mut impl WritableBuffer) {
1088        buf.write((*self).into());
1089    }
1090}
1091
1092impl FromBytes for Opcode {
1093    type Error = OpcodeParseError;
1094
1095    fn from_bytes(source: &mut BufferIterator) -> Result<Self, Self::Error> {
1096        let value = source.next().ok_or(OpcodeParseError::EOF)?;
1097        let opcode = Opcode::from(value);
1098
1099        match opcode {
1100            Opcode::Bogus => Err(OpcodeParseError::InvalidOpcode(value)),
1101            _ => Ok(opcode),
1102        }
1103    }
1104}
1105
1106#[cfg(test)]
1107mod tests {
1108    use super::*;
1109
1110    #[test]
1111    fn null_to_bytes() {
1112        let v = KOSValue::Null;
1113
1114        let mut buf = Vec::with_capacity(1);
1115
1116        v.to_bytes(&mut buf);
1117
1118        assert_eq!(buf, vec![0]);
1119    }
1120
1121    #[test]
1122    fn bool_to_bytes() {
1123        let v1 = KOSValue::Bool(true);
1124        let v2 = KOSValue::Bool(false);
1125
1126        let mut buf = Vec::with_capacity(2);
1127
1128        v1.to_bytes(&mut buf);
1129
1130        assert_eq!(buf, vec![1, 1]);
1131
1132        buf.clear();
1133        v2.to_bytes(&mut buf);
1134
1135        assert_eq!(buf, vec![1, 0]);
1136    }
1137
1138    #[test]
1139    fn byte_to_bytes() {
1140        let v1 = KOSValue::Byte(0);
1141        let v2 = KOSValue::Byte(-128);
1142
1143        let mut buf = Vec::with_capacity(2);
1144
1145        v1.to_bytes(&mut buf);
1146
1147        assert_eq!(buf, vec![2, 0]);
1148
1149        buf.clear();
1150        v2.to_bytes(&mut buf);
1151
1152        assert_eq!(buf, vec![2, -128i8 as u8]);
1153    }
1154
1155    #[test]
1156    fn int16_to_bytes() {
1157        let v1 = KOSValue::Int16(526);
1158
1159        let mut buf = Vec::with_capacity(3);
1160
1161        v1.to_bytes(&mut buf);
1162
1163        assert_eq!(buf, vec![3, 0b00001110, 0b00000010]);
1164    }
1165
1166    #[test]
1167    fn int32_to_bytes() {
1168        let v1 = KOSValue::Int32(-764);
1169
1170        let mut buf = Vec::with_capacity(5);
1171
1172        v1.to_bytes(&mut buf);
1173
1174        assert_eq!(buf, vec![4, 0b00000100, 0b11111101, 0b11111111, 0b11111111]);
1175    }
1176
1177    #[test]
1178    fn float_to_bytes() {
1179        let v1 = KOSValue::Float(3.14159);
1180
1181        let mut buf = Vec::with_capacity(5);
1182
1183        v1.to_bytes(&mut buf);
1184
1185        assert_eq!(buf, vec![5, 208, 15, 73, 64]);
1186    }
1187
1188    #[test]
1189    fn double_to_bytes() {
1190        let v1 = KOSValue::Double(3.14159);
1191
1192        let mut buf = Vec::with_capacity(9);
1193
1194        v1.to_bytes(&mut buf);
1195
1196        assert_eq!(buf, vec![6, 110, 134, 27, 240, 249, 33, 9, 64]);
1197    }
1198
1199    #[test]
1200    fn string_to_bytes() {
1201        let v1 = KOSValue::String(String::from("test str"));
1202
1203        let mut buf = Vec::with_capacity(10);
1204
1205        v1.to_bytes(&mut buf);
1206
1207        assert_eq!(
1208            buf,
1209            vec![7, 8, b't', b'e', b's', b't', b' ', b's', b't', b'r']
1210        );
1211    }
1212
1213    #[test]
1214    fn argmarker_to_bytes() {
1215        let v1 = KOSValue::ArgMarker;
1216
1217        let mut buf = Vec::with_capacity(1);
1218
1219        v1.to_bytes(&mut buf);
1220
1221        assert_eq!(buf, vec![8]);
1222    }
1223
1224    #[test]
1225    fn scalarint_to_bytes() {
1226        let v1 = KOSValue::ScalarInt(-1267);
1227
1228        let mut buf = Vec::with_capacity(5);
1229
1230        v1.to_bytes(&mut buf);
1231
1232        assert_eq!(buf, vec![9, 0b00001101, 0b11111011, 0b11111111, 0b11111111]);
1233    }
1234
1235    #[test]
1236    fn scalardouble_to_bytes() {
1237        let v1 = KOSValue::ScalarDouble(3.14159);
1238
1239        let mut buf = Vec::with_capacity(9);
1240
1241        v1.to_bytes(&mut buf);
1242
1243        assert_eq!(buf, vec![10, 110, 134, 27, 240, 249, 33, 9, 64]);
1244    }
1245
1246    #[test]
1247    fn boolvalue_to_bytes() {
1248        let v1 = KOSValue::BoolValue(true);
1249        let v2 = KOSValue::BoolValue(false);
1250
1251        let mut buf = Vec::with_capacity(2);
1252
1253        v1.to_bytes(&mut buf);
1254
1255        assert_eq!(buf, vec![11, 1]);
1256
1257        buf.clear();
1258        v2.to_bytes(&mut buf);
1259
1260        assert_eq!(buf, vec![11, 0]);
1261    }
1262
1263    #[test]
1264    fn stringvalue_to_bytes() {
1265        let v1 = KOSValue::StringValue(String::from("hello"));
1266
1267        let mut buf = Vec::with_capacity(7);
1268
1269        v1.to_bytes(&mut buf);
1270
1271        assert_eq!(buf, vec![12, 5, b'h', b'e', b'l', b'l', b'o']);
1272    }
1273}