snarkvm_circuit_environment/helpers/
mode.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkVM 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
16use crate::prelude::*;
17use snarkvm_utilities::{
18    FromBytes,
19    ToBytes,
20    error,
21    io::{Read, Result as IoResult, Write},
22};
23
24#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
25pub enum Mode {
26    Constant,
27    Public,
28    Private,
29}
30
31impl Mode {
32    /// Returns `true` if the mode is a constant.
33    pub const fn is_constant(&self) -> bool {
34        matches!(self, Self::Constant)
35    }
36
37    /// Returns `true` if the mode is public.
38    pub const fn is_public(&self) -> bool {
39        matches!(self, Self::Public)
40    }
41
42    /// Returns `true` if the mode is private.
43    pub const fn is_private(&self) -> bool {
44        matches!(self, Self::Private)
45    }
46
47    /// Parses a string into a mode.
48    #[inline]
49    pub fn parse(string: &str) -> ParserResult<Self> {
50        alt((
51            map(tag("constant"), |_| Self::Constant),
52            map(tag("public"), |_| Self::Public),
53            map(tag("private"), |_| Self::Private),
54        ))(string)
55    }
56
57    /// A static helper to deduce the mode from a list of modes.
58    #[inline]
59    pub fn combine<M: IntoIterator<Item = Mode>>(starting_mode: Mode, modes: M) -> Mode {
60        // Initialize the current mode.
61        let mut current_mode = starting_mode;
62        // Intuition: Start from `Mode::Constant`, and see if one needs to lift to `Mode::Public` or `Mode::Private`.
63        //   - If `current_mode == Mode::Constant`, then `current_mode = next_mode`.
64        //   - If `current_mode == Mode::Public` && `next_mode == Mode::Private`, then `current_mode = next_mode`.
65        //   - Otherwise, do nothing.
66        for next_mode in modes {
67            // If the current mode is `Mode::Private`, we can return early.
68            if current_mode.is_private() {
69                break;
70            }
71            // Check if the current mode matches the next mode.
72            if current_mode != next_mode {
73                match (current_mode, next_mode) {
74                    (Mode::Constant, Mode::Public)
75                    | (Mode::Constant, Mode::Private)
76                    | (Mode::Public, Mode::Private) => current_mode = next_mode,
77                    (_, _) => (), // Do nothing.
78                }
79            }
80        }
81        current_mode
82    }
83}
84
85impl IntoIterator for Mode {
86    type IntoIter = std::iter::Once<Self>;
87    type Item = Mode;
88
89    /// Returns an iterator over the mode.
90    fn into_iter(self) -> Self::IntoIter {
91        std::iter::once(self)
92    }
93}
94
95impl FromStr for Mode {
96    type Err = Error;
97
98    /// Parses a string into a mode.
99    #[inline]
100    fn from_str(string: &str) -> Result<Self> {
101        match Self::parse(string) {
102            Ok((remainder, object)) => {
103                // Ensure the remainder is empty.
104                ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
105                // Return the object.
106                Ok(object)
107            }
108            Err(error) => bail!("Failed to parse string. {error}"),
109        }
110    }
111}
112
113impl Display for Mode {
114    /// Formats the mode as a lowercase string.
115    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
116        match self {
117            Self::Constant => write!(f, "constant"),
118            Self::Public => write!(f, "public"),
119            Self::Private => write!(f, "private"),
120        }
121    }
122}
123
124impl ToBytes for Mode {
125    /// Writes the mode to the writer.
126    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
127        (*self as u8).write_le(&mut writer)
128    }
129}
130
131impl FromBytes for Mode {
132    /// Reads the mode from the reader.
133    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
134        let mode = u8::read_le(&mut reader)?;
135        match mode {
136            0 => Ok(Self::Constant),
137            1 => Ok(Self::Public),
138            2 => Ok(Self::Private),
139            _ => Err(error("Invalid mode")),
140        }
141    }
142}