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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
use super::{hasher, Box, Digest, Felt, Operation, Vec};
use crate::DecoratorList;
use core::fmt;

mod call_block;
mod dyn_block;
mod join_block;
mod loop_block;
mod proxy_block;
mod span_block;
mod split_block;

pub use call_block::Call;
pub use dyn_block::Dyn;
pub use join_block::Join;
pub use loop_block::Loop;
pub use proxy_block::Proxy;
pub use span_block::{
    get_span_op_group_count, OpBatch, Span, BATCH_SIZE as OP_BATCH_SIZE,
    GROUP_SIZE as OP_GROUP_SIZE,
};
pub use split_block::Split;

// PROGRAM BLOCK
// ================================================================================================
/// TODO: add comments
#[derive(Clone, Debug)]
pub enum CodeBlock {
    Span(Span),
    Join(Join),
    Split(Split),
    Loop(Loop),
    Call(Call),
    Dyn(Dyn),
    Proxy(Proxy),
}

impl CodeBlock {
    // CONSTRUCTORS
    // --------------------------------------------------------------------------------------------

    /// Returns a new Span block instantiated with the provided operations.
    pub fn new_span(operations: Vec<Operation>) -> Self {
        Self::Span(Span::new(operations))
    }

    /// Returns a new Span block instantiated with the provided operations and decorator list.
    pub fn new_span_with_decorators(operations: Vec<Operation>, decorators: DecoratorList) -> Self {
        Self::Span(Span::with_decorators(operations, decorators))
    }

    /// TODO: add comments
    pub fn new_join(blocks: [CodeBlock; 2]) -> Self {
        Self::Join(Join::new(blocks))
    }

    /// TODO: add comments
    pub fn new_split(t_branch: CodeBlock, f_branch: CodeBlock) -> Self {
        Self::Split(Split::new(t_branch, f_branch))
    }

    /// TODO: add comments
    pub fn new_loop(body: CodeBlock) -> Self {
        Self::Loop(Loop::new(body))
    }

    /// TODO: add comments
    pub fn new_call(fn_hash: Digest) -> Self {
        Self::Call(Call::new(fn_hash))
    }

    /// TODO: add comments
    pub fn new_syscall(fn_hash: Digest) -> Self {
        Self::Call(Call::new_syscall(fn_hash))
    }

    /// TODO: add comments
    pub fn new_dyn() -> Self {
        Self::Dyn(Dyn::new())
    }

    /// TODO: add comments
    pub fn new_dyncall() -> Self {
        Self::Call(Call::new(Dyn::dyn_hash()))
    }

    /// TODO: add comments
    pub fn new_proxy(code_hash: Digest) -> Self {
        Self::Proxy(Proxy::new(code_hash))
    }

    // PUBLIC ACCESSORS
    // --------------------------------------------------------------------------------------------

    /// Returns true if this code block is a [Span] block.
    pub fn is_span(&self) -> bool {
        matches!(self, CodeBlock::Span(_))
    }

    /// Returns a hash of this code block.
    pub fn hash(&self) -> Digest {
        match self {
            CodeBlock::Span(block) => block.hash(),
            CodeBlock::Join(block) => block.hash(),
            CodeBlock::Split(block) => block.hash(),
            CodeBlock::Loop(block) => block.hash(),
            CodeBlock::Call(block) => block.hash(),
            CodeBlock::Dyn(block) => block.hash(),
            CodeBlock::Proxy(block) => block.hash(),
        }
    }

    /// Returns the domain of the code block
    pub fn domain(&self) -> Felt {
        match self {
            CodeBlock::Call(block) => block.domain(),
            CodeBlock::Dyn(_) => Dyn::DOMAIN,
            CodeBlock::Join(_) => Join::DOMAIN,
            CodeBlock::Loop(_) => Loop::DOMAIN,
            CodeBlock::Span(_) => Span::DOMAIN,
            CodeBlock::Split(_) => Split::DOMAIN,
            CodeBlock::Proxy(_) => panic!("Can't fetch `domain` for a `Proxy` block!"),
        }
    }
}

impl fmt::Display for CodeBlock {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            CodeBlock::Span(block) => write!(f, "{block}"),
            CodeBlock::Join(block) => write!(f, "{block}"),
            CodeBlock::Split(block) => write!(f, "{block}"),
            CodeBlock::Loop(block) => write!(f, "{block}"),
            CodeBlock::Call(block) => write!(f, "{block}"),
            CodeBlock::Dyn(block) => write!(f, "{block}",),
            CodeBlock::Proxy(block) => write!(f, "{block}"),
        }
    }
}