forked from starkware-libs/cairo
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathzeroable.cairo
More file actions
154 lines (134 loc) · 4.53 KB
/
Copy pathzeroable.cairo
File metadata and controls
154 lines (134 loc) · 4.53 KB
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//! Types and traits for handling non-zero values and zero checking operations.
//!
//! This module provides the [`NonZero`] wrapper type which guarantees that a value is never
//! zero.
//! The [`Zeroable`] trait is meant for internal use only. The public-facing equivalent is the
//! [`Zero`] trait.
//!
//! [`Zero`]: core::num::traits::zero::Zero
/// A trait for types that have a concept of zero and can be compared to zero.
///
/// This trait is useful for numeric types or any type that has an additive identity element.
pub(crate) trait Zeroable<T> {
/// Returns the additive identity element of `self`, 0.
///
/// This method should return a value that, when added to any other value of type `T`,
/// does not change that value.
///
/// # Examples
///
/// ```
/// assert!(Zeroable::<i32>::zero() == 0);
/// ```
#[must_use]
fn zero() -> T;
/// Returns whether `self` is equal to 0, the additive identity element.
///
/// # Examples
///
/// ```
/// assert!(0.is_zero());
/// assert!(!5.is_zero());
/// ```
#[must_use]
fn is_zero(self: T) -> bool;
/// Returns whether `self` is not equal to 0, the additive identity element.
///
/// This method is the logical inverse of `is_zero()`.
///
/// # Examples
///
/// ```
/// assert!(5.is_non_zero());
/// assert!(!0.is_non_zero());
/// ```
#[must_use]
fn is_non_zero(self: T) -> bool;
}
/// Provides an implementation of the `Zeroable` trait for types that implement `Zero`.
pub(crate) mod zero_based {
/// Implements `Zeroable` for any type that implements `Zero`, `Drop`, and `Copy`.
pub(crate) impl ZeroableImpl<
T, impl ZeroImpl: crate::num::traits::Zero<T>, +Drop<T>, +Copy<T>,
> of super::Zeroable<T> {
fn zero() -> T {
ZeroImpl::zero()
}
#[inline]
fn is_zero(self: T) -> bool {
ZeroImpl::is_zero(@self)
}
#[inline]
fn is_non_zero(self: T) -> bool {
ZeroImpl::is_non_zero(@self)
}
}
}
pub(crate) impl Felt252Zeroable = zero_based::ZeroableImpl<felt252>;
/// A wrapper type for non-zero values of type T.
///
/// This type guarantees that the wrapped value is never zero.
pub extern type NonZero<T>;
impl NonZeroCopy<T> of Copy<NonZero<T>>;
impl NonZeroDrop<T> of Drop<NonZero<T>>;
pub(crate) mod non_zero_neg {
pub impl Impl<T, +Neg<T>, +TryInto<T, NonZero<T>>> of Neg<NonZero<T>> {
fn neg(a: NonZero<T>) -> NonZero<T> {
// TODO(orizi): Optimize using bounded integers.
let value: T = a.into();
let negated: T = -value;
negated.try_into().unwrap()
}
}
}
impl NonZeroI8Neg = non_zero_neg::Impl<i8>;
impl NonZeroI16Neg = non_zero_neg::Impl<i16>;
impl NonZeroI32Neg = non_zero_neg::Impl<i32>;
impl NonZeroI64Neg = non_zero_neg::Impl<i64>;
impl NonZeroI128Neg = non_zero_neg::Impl<i128>;
impl NonZeroFelt252Neg = non_zero_neg::Impl<felt252>;
/// Represents the result of checking whether a value is zero.
pub(crate) enum IsZeroResult<T> {
/// Indicates that the value is zero.
Zero,
/// Indicates that the value is non-zero, wrapping it in a `NonZero<T>`.
NonZero: NonZero<T>,
}
/// Unwraps a `NonZero<T>` to retrieve the underlying value of type `T`.
extern const fn unwrap_non_zero<T>(a: NonZero<T>) -> T nopanic;
pub(crate) impl NonZeroIntoImpl<T> of Into<NonZero<T>, T> {
const fn into(self: NonZero<T>) -> T nopanic {
unwrap_non_zero(self)
}
}
impl IsZeroResultIntoBool<T, +Drop<T>> of Into<IsZeroResult<T>, bool> {
fn into(self: IsZeroResult<T>) -> bool {
match self {
IsZeroResult::Zero => true,
IsZeroResult::NonZero(_) => false,
}
}
}
impl NonZeroPartialEq<T, +PartialEq<T>, +Copy<T>, +Drop<T>> of PartialEq<NonZero<T>> {
#[inline]
fn eq(lhs: @NonZero<T>, rhs: @NonZero<T>) -> bool {
let lhs: T = (*lhs).into();
let rhs: T = (*rhs).into();
lhs == rhs
}
#[inline]
fn ne(lhs: @NonZero<T>, rhs: @NonZero<T>) -> bool {
let lhs: T = (*lhs).into();
let rhs: T = (*rhs).into();
lhs != rhs
}
}
impl NonZeroSerde<T, +Serde<T>, +Copy<T>, +Drop<T>, +TryInto<T, NonZero<T>>> of Serde<NonZero<T>> {
fn serialize(self: @NonZero<T>, ref output: Array<felt252>) {
let value: T = (*self).into();
value.serialize(ref output);
}
fn deserialize(ref serialized: Span<felt252>) -> Option<NonZero<T>> {
Serde::<T>::deserialize(ref serialized)?.try_into()
}
}