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