-
Notifications
You must be signed in to change notification settings - Fork 219
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add some traits to the stdlib (#3796)
# Description ## Problem\* ## Summary\* Adds traits for `Default`, `Add`, `Sub`, `Mul`, `Div`, and `Eq` to the stdlib. Note that this does not implement operator overloading so the operator traits must be called by name. We also have no way currently of implementing a trait for all integer sizes so I've manually implemented only some common ones. Let me know if there are other impls I should add. ## Additional Context ## Documentation\* Check one: - [ ] No documentation needed. - [x] Documentation included in this PR. - [ ] **[Exceptional Case]** Documentation to be submitted in a separate PR. # PR Checklist\* - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings.
- Loading branch information
Showing
5 changed files
with
316 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
--- | ||
title: Traits | ||
description: Noir's stdlib provides a few commonly used traits. | ||
keywords: [traits, trait, interface, protocol, default, add, eq] | ||
--- | ||
|
||
## `std::default` | ||
|
||
### `std::default::Default` | ||
|
||
```rust | ||
trait Default { | ||
fn default() -> Self; | ||
} | ||
``` | ||
|
||
Constructs a default value of a type. | ||
|
||
Implementations: | ||
```rust | ||
impl Default for Field { .. } | ||
|
||
impl Default for i8 { .. } | ||
impl Default for i16 { .. } | ||
impl Default for i32 { .. } | ||
impl Default for i64 { .. } | ||
|
||
impl Default for u8 { .. } | ||
impl Default for u16 { .. } | ||
impl Default for u32 { .. } | ||
impl Default for u64 { .. } | ||
|
||
impl Default for () { .. } | ||
impl Default for bool { .. } | ||
|
||
impl<T, N> Default for [T; N] | ||
where T: Default { .. } | ||
|
||
impl<A, B> Default for (A, B) | ||
where A: Default, B: Default { .. } | ||
|
||
impl<A, B, C> Default for (A, B, C) | ||
where A: Default, B: Default, C: Default { .. } | ||
|
||
impl<A, B, C, D> Default for (A, B, C, D) | ||
where A: Default, B: Default, C: Default, D: Default { .. } | ||
|
||
impl<A, B, C, D, E> Default for (A, B, C, D, E) | ||
where A: Default, B: Default, C: Default, D: Default, E: Default { .. } | ||
``` | ||
|
||
For primitive integer types, the return value of `default` is `0`. Container | ||
types such as arrays are filled with default values of their element type. | ||
|
||
## `std::ops` | ||
|
||
### `std::ops::Eq` | ||
|
||
```rust | ||
trait Eq { | ||
fn eq(self, other: Self) -> bool; | ||
} | ||
``` | ||
Returns `true` if `self` is equal to `other`. | ||
|
||
Implementations: | ||
```rust | ||
impl Eq for Field { .. } | ||
|
||
impl Eq for i8 { .. } | ||
impl Eq for i16 { .. } | ||
impl Eq for i32 { .. } | ||
impl Eq for i64 { .. } | ||
|
||
impl Eq for u8 { .. } | ||
impl Eq for u16 { .. } | ||
impl Eq for u32 { .. } | ||
impl Eq for u64 { .. } | ||
|
||
impl Eq for () { .. } | ||
impl Eq for bool { .. } | ||
|
||
impl<T, N> Eq for [T; N] | ||
where T: Eq { .. } | ||
|
||
impl<A, B> Eq for (A, B) | ||
where A: Eq, B: Eq { .. } | ||
|
||
impl<A, B, C> Eq for (A, B, C) | ||
where A: Eq, B: Eq, C: Eq { .. } | ||
|
||
impl<A, B, C, D> Eq for (A, B, C, D) | ||
where A: Eq, B: Eq, C: Eq, D: Eq { .. } | ||
|
||
impl<A, B, C, D, E> Eq for (A, B, C, D, E) | ||
where A: Eq, B: Eq, C: Eq, D: Eq, E: Eq { .. } | ||
``` | ||
|
||
### `std::ops::Add`, `std::ops::Sub`, `std::ops::Mul`, and `std::ops::Div` | ||
|
||
These traits abstract over addition, subtraction, multiplication, and division respectively. | ||
Although Noir does not currently have operator overloading, in the future implementing these | ||
traits for a given type will also allow that type to be used with the corresponding operator | ||
for that trait (`+` for Add, etc) in addition to the normal method names. | ||
|
||
```rust | ||
trait Add { | ||
fn add(self, other: Self) -> Self; | ||
} | ||
|
||
trait Sub { | ||
fn sub(self, other: Self) -> Self; | ||
} | ||
|
||
trait Mul { | ||
fn mul(self, other: Self) -> Self; | ||
} | ||
|
||
trait Div { | ||
fn div(self, other: Self) -> Self; | ||
} | ||
``` | ||
|
||
The implementations block below is given for the `Add` trait, but the same types that implement | ||
`Add` also implement `Sub`, `Mul`, and `Div`. | ||
|
||
Implementations: | ||
```rust | ||
impl Add for Field { .. } | ||
|
||
impl Add for i8 { .. } | ||
impl Add for i16 { .. } | ||
impl Add for i32 { .. } | ||
impl Add for i64 { .. } | ||
|
||
impl Add for u8 { .. } | ||
impl Add for u16 { .. } | ||
impl Add for u32 { .. } | ||
impl Add for u64 { .. } | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
trait Default { | ||
fn default() -> Self; | ||
} | ||
|
||
impl Default for Field { fn default() -> Field { 0 } } | ||
|
||
impl Default for u8 { fn default() -> u8 { 0 } } | ||
impl Default for u16 { fn default() -> u16 { 0 } } | ||
impl Default for u32 { fn default() -> u32 { 0 } } | ||
impl Default for u64 { fn default() -> u64 { 0 } } | ||
|
||
impl Default for i8 { fn default() -> i8 { 0 } } | ||
impl Default for i16 { fn default() -> i16 { 0 } } | ||
impl Default for i32 { fn default() -> i32 { 0 } } | ||
impl Default for i64 { fn default() -> i64 { 0 } } | ||
|
||
impl Default for () { fn default() -> () { () } } | ||
impl Default for bool { fn default() -> bool { false } } | ||
|
||
impl<T, N> Default for [T; N] where T: Default { | ||
fn default() -> [T; N] { | ||
[T::default(); N] | ||
} | ||
} | ||
|
||
impl<A, B> Default for (A, B) where A: Default, B: Default { | ||
fn default() -> (A, B) { | ||
(A::default(), B::default()) | ||
} | ||
} | ||
|
||
impl<A, B, C> Default for (A, B, C) where A: Default, B: Default, C: Default { | ||
fn default() -> (A, B, C) { | ||
(A::default(), B::default(), C::default()) | ||
} | ||
} | ||
|
||
impl<A, B, C, D> Default for (A, B, C, D) where A: Default, B: Default, C: Default, D: Default { | ||
fn default() -> (A, B, C, D) { | ||
(A::default(), B::default(), C::default(), D::default()) | ||
} | ||
} | ||
|
||
impl<A, B, C, D, E> Default for (A, B, C, D, E) where A: Default, B: Default, C: Default, D: Default, E: Default { | ||
fn default() -> (A, B, C, D, E) { | ||
(A::default(), B::default(), C::default(), D::default(), E::default()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
|
||
trait Add { | ||
fn add(self, other: Self) -> Self; | ||
} | ||
|
||
impl Add for Field { fn add(self, other: Field) -> Field { self + other } } | ||
|
||
impl Add for u8 { fn add(self, other: u8) -> u8 { self + other } } | ||
impl Add for u16 { fn add(self, other: u16) -> u16 { self + other } } | ||
impl Add for u32 { fn add(self, other: u32) -> u32 { self + other } } | ||
impl Add for u64 { fn add(self, other: u64) -> u64 { self + other } } | ||
|
||
impl Add for i8 { fn add(self, other: i8) -> i8 { self + other } } | ||
impl Add for i16 { fn add(self, other: i16) -> i16 { self + other } } | ||
impl Add for i32 { fn add(self, other: i32) -> i32 { self + other } } | ||
impl Add for i64 { fn add(self, other: i64) -> i64 { self + other } } | ||
|
||
trait Sub { | ||
fn sub(self, other: Self) -> Self; | ||
} | ||
|
||
impl Sub for Field { fn sub(self, other: Field) -> Field { self - other } } | ||
|
||
impl Sub for u8 { fn sub(self, other: u8) -> u8 { self - other } } | ||
impl Sub for u16 { fn sub(self, other: u16) -> u16 { self - other } } | ||
impl Sub for u32 { fn sub(self, other: u32) -> u32 { self - other } } | ||
impl Sub for u64 { fn sub(self, other: u64) -> u64 { self - other } } | ||
|
||
impl Sub for i8 { fn sub(self, other: i8) -> i8 { self - other } } | ||
impl Sub for i16 { fn sub(self, other: i16) -> i16 { self - other } } | ||
impl Sub for i32 { fn sub(self, other: i32) -> i32 { self - other } } | ||
impl Sub for i64 { fn sub(self, other: i64) -> i64 { self - other } } | ||
|
||
trait Mul { | ||
fn mul(self, other: Self) -> Self; | ||
} | ||
|
||
impl Mul for Field { fn mul(self, other: Field) -> Field { self * other } } | ||
|
||
impl Mul for u8 { fn mul(self, other: u8) -> u8 { self * other } } | ||
impl Mul for u16 { fn mul(self, other: u16) -> u16 { self * other } } | ||
impl Mul for u32 { fn mul(self, other: u32) -> u32 { self * other } } | ||
impl Mul for u64 { fn mul(self, other: u64) -> u64 { self * other } } | ||
|
||
impl Mul for i8 { fn mul(self, other: i8) -> i8 { self * other } } | ||
impl Mul for i16 { fn mul(self, other: i16) -> i16 { self * other } } | ||
impl Mul for i32 { fn mul(self, other: i32) -> i32 { self * other } } | ||
impl Mul for i64 { fn mul(self, other: i64) -> i64 { self * other } } | ||
|
||
trait Div { | ||
fn div(self, other: Self) -> Self; | ||
} | ||
|
||
impl Div for Field { fn div(self, other: Field) -> Field { self / other } } | ||
|
||
impl Div for u8 { fn div(self, other: u8) -> u8 { self / other } } | ||
impl Div for u16 { fn div(self, other: u16) -> u16 { self / other } } | ||
impl Div for u32 { fn div(self, other: u32) -> u32 { self / other } } | ||
impl Div for u64 { fn div(self, other: u64) -> u64 { self / other } } | ||
|
||
impl Div for i8 { fn div(self, other: i8) -> i8 { self / other } } | ||
impl Div for i16 { fn div(self, other: i16) -> i16 { self / other } } | ||
impl Div for i32 { fn div(self, other: i32) -> i32 { self / other } } | ||
impl Div for i64 { fn div(self, other: i64) -> i64 { self / other } } | ||
|
||
trait Eq { | ||
fn eq(self, other: Self) -> bool; | ||
} | ||
|
||
impl Eq for Field { fn eq(self, other: Field) -> bool { self == other } } | ||
|
||
impl Eq for u8 { fn eq(self, other: u8) -> bool { self == other } } | ||
impl Eq for u16 { fn eq(self, other: u16) -> bool { self == other } } | ||
impl Eq for u32 { fn eq(self, other: u32) -> bool { self == other } } | ||
impl Eq for u64 { fn eq(self, other: u64) -> bool { self == other } } | ||
|
||
impl Eq for i8 { fn eq(self, other: i8) -> bool { self == other } } | ||
impl Eq for i16 { fn eq(self, other: i16) -> bool { self == other } } | ||
impl Eq for i32 { fn eq(self, other: i32) -> bool { self == other } } | ||
impl Eq for i64 { fn eq(self, other: i64) -> bool { self == other } } | ||
|
||
impl Eq for () { fn eq(_self: Self, _other: ()) -> bool { true } } | ||
impl Eq for bool { fn eq(self, other: bool) -> bool { self == other } } | ||
|
||
impl<T, N> Eq for [T; N] where T: Eq { | ||
fn eq(self, other: [T; N]) -> bool { | ||
let mut result = true; | ||
for i in 0 .. self.len() { | ||
result &= self[i].eq(other[i]); | ||
} | ||
result | ||
} | ||
} | ||
|
||
impl<A, B> Eq for (A, B) where A: Eq, B: Eq { | ||
fn eq(self, other: (A, B)) -> bool { | ||
self.0.eq(other.0) & self.1.eq(other.1) | ||
} | ||
} | ||
|
||
impl<A, B, C> Eq for (A, B, C) where A: Eq, B: Eq, C: Eq { | ||
fn eq(self, other: (A, B, C)) -> bool { | ||
self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2) | ||
} | ||
} | ||
|
||
impl<A, B, C, D> Eq for (A, B, C, D) where A: Eq, B: Eq, C: Eq, D: Eq { | ||
fn eq(self, other: (A, B, C, D)) -> bool { | ||
self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2) & self.3.eq(other.3) | ||
} | ||
} | ||
|
||
impl<A, B, C, D, E> Eq for (A, B, C, D, E) where A: Eq, B: Eq, C: Eq, D: Eq, E: Eq { | ||
fn eq(self, other: (A, B, C, D, E)) -> bool { | ||
self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2) & self.3.eq(other.3) & self.4.eq(other.4) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,21 @@ | ||
fn main() { | ||
let a: [[[[Field; 2]; 2]; 2]; 2] = [[[[1, 2], [3, 4]], [[5, 6], [7, 8]]], [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]]; | ||
assert(a.eq(a)); | ||
assert(a.my_eq(a)); | ||
} | ||
|
||
trait Eq { | ||
fn eq(self, other: Self) -> bool; | ||
trait MyEq { | ||
fn my_eq(self, other: Self) -> bool; | ||
} | ||
|
||
impl<T> Eq for [T; 2] where T: Eq { | ||
fn eq(self, other: Self) -> bool { | ||
self[0].eq(other[0]) | ||
& self[0].eq(other[0]) | ||
impl<T> MyEq for [T; 2] where T: MyEq { | ||
fn my_eq(self, other: Self) -> bool { | ||
self[0].my_eq(other[0]) | ||
& self[0].my_eq(other[0]) | ||
} | ||
} | ||
// Impl for u32 but not Field | ||
impl Eq for u32 { | ||
fn eq(self, other: Self) -> bool { | ||
impl MyEq for u32 { | ||
fn my_eq(self, other: Self) -> bool { | ||
self == other | ||
} | ||
} |