1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
use crate::byte_readable::ByteReadable;
use crate::exception::Exception;
use crate::runtime::exceptions::ConstantNotFound;
use crate::InstructionPointer;
use std::fmt;
use std::fmt::{Debug, Formatter};

pub struct Chunk<Constant> {
    pub constants: Vec<Constant>,
    pub code: Vec<u8>,
}

pub struct Code<Constant> {
    pub chunks: Vec<Chunk<Constant>>,
}

impl<Constant> Code<Constant> {
    pub fn get_constant(
        &self,
        chunk_id: usize,
        constant_id: usize,
    ) -> Result<&Constant, Exception> {
        self.get_chunk(chunk_id)
            .and_then(|chunk| chunk.constants.get(constant_id))
            .ok_or_else(|| Exception::from(ConstantNotFound(chunk_id, constant_id)))
    }

    pub fn get_chunk(&self, chunk_id: usize) -> Option<&Chunk<Constant>> {
        self.chunks.get(chunk_id)
    }
}

impl<Constant> ByteReadable<InstructionPointer> for Code<Constant> {
    fn read(&self, ptr: &mut InstructionPointer) -> Option<u8> {
        let chunk = self.get_chunk(ptr.chunk_id)?;
        ptr.read_and_advance(chunk)
    }

    fn has_next(&self, ptr: &InstructionPointer) -> bool {
        let chunk = self.get_chunk(ptr.chunk_id).unwrap();
        ptr.instruction_pointer < chunk.code.len()
    }
}

impl<Constant: Debug> Debug for Chunk<Constant> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.debug_struct("Chunk")
            .field("constants", &self.constants)
            .field("code", &self.code)
            .finish()
    }
}

impl<Constant: Debug> Debug for Code<Constant> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.debug_list().entries(&self.chunks).finish()
    }
}