snarkvm_circuit_environment/traits/
eject.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::Mode;
17
18/// Operations to eject from a circuit environment into primitive form.
19pub trait Eject {
20    type Primitive;
21
22    ///
23    /// Ejects the mode and primitive value of the circuit type.
24    ///
25    fn eject(&self) -> (Mode, Self::Primitive) {
26        (self.eject_mode(), self.eject_value())
27    }
28
29    ///
30    /// Ejects the mode of the circuit type.
31    ///
32    fn eject_mode(&self) -> Mode;
33
34    ///
35    /// Ejects the circuit type as a primitive value.
36    ///
37    fn eject_value(&self) -> Self::Primitive;
38
39    ///
40    /// Returns `true` if the circuit is a constant.
41    ///
42    fn is_constant(&self) -> bool {
43        self.eject_mode().is_constant()
44    }
45
46    ///
47    /// Returns `true` if the circuit is a public.
48    ///
49    fn is_public(&self) -> bool {
50        self.eject_mode().is_public()
51    }
52
53    ///
54    /// Returns `true` if the circuit is a private.
55    ///
56    fn is_private(&self) -> bool {
57        self.eject_mode().is_private()
58    }
59}
60
61/********************/
62/****** Arrays ******/
63/********************/
64
65impl Eject for Vec<Mode> {
66    type Primitive = Vec<Mode>;
67
68    /// A helper method to deduce the mode from a list of `Eject` circuits.
69    #[inline]
70    fn eject_mode(&self) -> Mode {
71        // TODO (howardwu): Determine if a default mode of `constant` is appropriate.
72        // Retrieve the mode of the first circuit.
73        match self.first() {
74            Some(first) => Mode::combine(*first, self.iter().copied().skip(1)),
75            // None => Mode::Constant,
76            None => panic!("Attempted to eject the mode on an empty circuit"),
77        }
78    }
79
80    /// Ejects the value from each circuit.
81    #[inline]
82    fn eject_value(&self) -> Self::Primitive {
83        self.clone()
84    }
85}
86
87impl<C: Eject<Primitive = P>, P> Eject for Vec<C> {
88    type Primitive = Vec<P>;
89
90    /// A helper method to deduce the mode from a list of `Eject` circuits.
91    #[inline]
92    fn eject_mode(&self) -> Mode {
93        self.as_slice().eject_mode()
94    }
95
96    /// Ejects the value from each circuit.
97    #[inline]
98    fn eject_value(&self) -> Self::Primitive {
99        self.as_slice().eject_value()
100    }
101}
102
103impl<C: Eject<Primitive = P>, P, const N: usize> Eject for [C; N] {
104    type Primitive = Vec<P>;
105
106    /// A helper method to deduce the mode from a list of `Eject` circuits.
107    #[inline]
108    fn eject_mode(&self) -> Mode {
109        self.as_slice().eject_mode()
110    }
111
112    /// Ejects the value from each circuit.
113    #[inline]
114    fn eject_value(&self) -> Self::Primitive {
115        self.as_slice().eject_value()
116    }
117}
118
119impl<C: Eject<Primitive = P>, P> Eject for &[C] {
120    type Primitive = Vec<P>;
121
122    /// A helper method to deduce the mode from a list of `Eject` circuits.
123    #[inline]
124    fn eject_mode(&self) -> Mode {
125        // TODO (howardwu): Determine if a default mode of `constant` is appropriate.
126        // Retrieve the mode of the first circuit.
127        match self.first() {
128            Some(first) => Mode::combine(first.eject_mode(), self.iter().skip(1).map(Eject::eject_mode)),
129            None => Mode::Constant,
130            // None => panic!("Attempted to eject the mode on an empty circuit"),
131        }
132    }
133
134    /// Ejects the value from each circuit.
135    #[inline]
136    fn eject_value(&self) -> Self::Primitive {
137        self.iter().map(Eject::eject_value).collect()
138    }
139}
140
141/********************/
142/****** Tuples ******/
143/********************/
144
145/// A helper macro to implement `Eject` for a tuple of `Eject` circuits.
146macro_rules! eject_tuple {
147    (($t0:ident, 0), $(($ty:ident, $idx:tt)),*) => {
148        impl<'a, $t0: Eject, $($ty: Eject),*> Eject for (&'a $t0, $(&'a $ty),*) {
149            type Primitive = ($t0::Primitive, $( $ty::Primitive ),*);
150
151            /// A helper method to deduce the mode from a tuple of `Eject` circuits.
152            #[inline]
153            fn eject_mode(&self) -> Mode {
154                Mode::combine(self.0.eject_mode(), [ $(self.$idx.eject_mode()),* ])
155            }
156
157            /// Ejects the value from each circuit.
158            #[inline]
159            fn eject_value(&self) -> Self::Primitive {
160                (self.0.eject_value(), $(self.$idx.eject_value()),*)
161            }
162        }
163
164        impl<'a, $t0: Eject, $($ty: Eject),*> Eject for &'a ($t0, $($ty),*) {
165            type Primitive = ($t0::Primitive, $( $ty::Primitive ),*);
166
167            /// A helper method to deduce the mode from a tuple of `Eject` circuits.
168            #[inline]
169            fn eject_mode(&self) -> Mode {
170                Mode::combine(self.0.eject_mode(), [ $(self.$idx.eject_mode()),* ])
171            }
172
173            /// Ejects the value from each circuit.
174            #[inline]
175            fn eject_value(&self) -> Self::Primitive {
176                (self.0.eject_value(), $(self.$idx.eject_value()),*)
177            }
178        }
179    }
180}
181
182eject_tuple!((C0, 0),);
183eject_tuple!((C0, 0), (C1, 1));
184eject_tuple!((C0, 0), (C1, 1), (C2, 2));
185eject_tuple!((C0, 0), (C1, 1), (C2, 2), (C3, 3));
186eject_tuple!((C0, 0), (C1, 1), (C2, 2), (C3, 3), (C4, 4));
187eject_tuple!((C0, 0), (C1, 1), (C2, 2), (C3, 3), (C4, 4), (C5, 5));
188eject_tuple!((C0, 0), (C1, 1), (C2, 2), (C3, 3), (C4, 4), (C5, 5), (C6, 6));
189eject_tuple!((C0, 0), (C1, 1), (C2, 2), (C3, 3), (C4, 4), (C5, 5), (C6, 6), (C7, 7));
190eject_tuple!((C0, 0), (C1, 1), (C2, 2), (C3, 3), (C4, 4), (C5, 5), (C6, 6), (C7, 7), (C8, 8));
191eject_tuple!((C0, 0), (C1, 1), (C2, 2), (C3, 3), (C4, 4), (C5, 5), (C6, 6), (C7, 7), (C8, 8), (C9, 9));
192eject_tuple!((C0, 0), (C1, 1), (C2, 2), (C3, 3), (C4, 4), (C5, 5), (C6, 6), (C7, 7), (C8, 8), (C9, 9), (C10, 10));
193#[rustfmt::skip] eject_tuple!((C0, 0), (C1, 1), (C2, 2), (C3, 3), (C4, 4), (C5, 5), (C6, 6), (C7, 7), (C8, 8), (C9, 9), (C10, 10), (C11, 11));
194#[rustfmt::skip] eject_tuple!((C0, 0), (C1, 1), (C2, 2), (C3, 3), (C4, 4), (C5, 5), (C6, 6), (C7, 7), (C8, 8), (C9, 9), (C10, 10), (C11, 11), (C12, 12));