Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add generic traits example #25

Merged
merged 6 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions noir_by_example/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
target
Prover.toml
Verifier.toml
4 changes: 4 additions & 0 deletions noir_by_example/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion noir_by_example/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[workspace]
members = [
"simple_macros/rust",
"loops/rust"
"loops/rust",
"generic_traits/rust"
]
resolver = "1"
3 changes: 2 additions & 1 deletion noir_by_example/Nargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[workspace]
members = [
"simple_macros/noir",
"loops/noir"
"loops/noir",
"generic_traits/noir"
]
7 changes: 7 additions & 0 deletions noir_by_example/generic_traits/noir/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "generic_traits"
type = "bin"
authors = [""]
compiler_version = ">=0.35.0"

[dependencies]
2 changes: 2 additions & 0 deletions noir_by_example/generic_traits/noir/Prover.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cost = "15"
start = "20"
84 changes: 84 additions & 0 deletions noir_by_example/generic_traits/noir/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// DCI (Data, Context, Interaction) example - keeps objects simple, and binds specific functions to them in their context of use

// ### DATA ###
struct ValueAccount {
balance: u32,
}

// Primitive functions for data object
trait ValueFunctions {
fn add(&mut self, val: u32);
fn sub(&mut self, val: u32);
}

impl ValueFunctions for ValueAccount {
fn add(&mut self, val: u32) {
self.balance += val;
}
fn sub(&mut self, val: u32) {
self.balance -= val;
}
}

// ### CONTEXT ###

// Example purchase context
// Buyer role
trait Buyer {
fn make_payment(&mut self, val: u32);
}

// impl <T:ValueFunctions> Buyer for T { // This works in rust
// impl <T> Buyer for T where T:ValueFunctions { // Valid noir, specifies value functions,
// but gives compilation error on line that calls Buyer function make_payment
impl Buyer for ValueAccount { // context needs to be aware of data object (not just trait)
fn make_payment(&mut self, val: u32) {
self.sub(val);
}
}

// Seller role
trait Seller {
fn receive_payment(&mut self, val: u32);
}

impl Seller for ValueAccount {
fn receive_payment(&mut self, val: u32) {
self.add(val);
}
}

// Define the purchase context with its generic roles
struct PurchaseContext<B, S> {
// Roles
buyer: &mut B,
seller: &mut S,
}

impl <B, S> PurchaseContext<B, S> where B: Buyer, S: Seller {
fn do_purchase(&mut self, amount: u32) {
self.buyer.make_payment(amount); // Compilation error "No matching impl found for `B: ValueFunctions`" when Buyer uses generic T
// self.buyer.receive_payment(amount); // correct compiler error, buyer role cannot receive_payment
self.seller.receive_payment(amount);
}
}

// ### INTERACTION ###

fn main(start: u32, cost: pub u32) {
jzaki marked this conversation as resolved.
Show resolved Hide resolved
assert(start >= cost, "Not enough start balance");
// create data object, can use all primitive functions
let mut acc1: ValueAccount = ValueAccount { balance: start };
let mut acc2: ValueAccount = ValueAccount { balance: start };

// create context for data object as
let mut purchase_context: PurchaseContext<ValueAccount, ValueAccount> = PurchaseContext::<ValueAccount, ValueAccount> { buyer: &mut acc1, seller: &mut acc2 };
purchase_context.do_purchase(cost);
assert(acc1.balance == start - cost, "Didn't spend");
assert(acc2.balance == start + cost, "Didn't receive");
}

#[test]
fn test_generic_traits() {
main(10, 5);
}
6 changes: 6 additions & 0 deletions noir_by_example/generic_traits/rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "generic_traits"
version = "0.1.0"
edition = "2021"

[dependencies]
88 changes: 88 additions & 0 deletions noir_by_example/generic_traits/rust/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// DCI (Data, Context, Interaction) example - keeps objects simple, and binds specific functions to them in their context of use


// ### DATA ###
struct ValueAccount {
balance: u32,
}

// Primitive functions for data object
trait ValueFunctions {
fn add(&mut self, val: u32);
fn sub(&mut self, val: u32);
}

impl ValueFunctions for ValueAccount {
fn add(&mut self, val: u32) {
self.balance += val;
}
fn sub(&mut self, val: u32) {
self.balance -= val;
}
}


// ### CONTEXT ###

// Example purchase context
// Buyer role
trait Buyer {
fn make_payment(&mut self, val: u32);
}

impl <T:ValueFunctions> Buyer for T {
fn make_payment(&mut self, val: u32) {
self.sub(val);
}
}

// Seller role
trait Seller {
fn receive_payment(&mut self, val: u32);
}

impl <T:ValueFunctions> Seller for T {
fn receive_payment(&mut self, val: u32) {
self.add(val);
}
}

// Define the purchase context with its generic roles
struct PurchaseContext<'b, 's, B, S> {
// Roles
buyer: &'b mut B,
seller: &'s mut S,
}

impl <B, S> PurchaseContext<'_, '_, B, S> where B: Buyer, S: Seller {
fn do_purchase(&mut self, amount: u32) {
self.buyer.make_payment(amount);
// self.buyer.receive_payment(amount); // correct compiler error, buyer role cannot receive_payment
self.seller.receive_payment(amount);
}
}


// ### INTERACTION ###

fn main(start: u32, cost: u32) {
assert!(start >= cost, "Not enough start balance");
// create data object, can use all primitive functions
let mut acc1: ValueAccount = ValueAccount { balance: start };
let mut acc2: ValueAccount = ValueAccount { balance: start };

// create context for data object as
let mut purchase_context: PurchaseContext<ValueAccount, ValueAccount> =
PurchaseContext::<ValueAccount, ValueAccount> {
buyer: &mut acc1, seller: &mut acc2
};
purchase_context.do_purchase(cost);
assert!(acc1.balance == start - cost, "Didn't spend");
assert!(acc2.balance == start + cost, "Didn't receive");
}


#[test]
fn test_generic_traits() {
main(10, 5);
}
1 change: 1 addition & 0 deletions noir_by_example/loops/noir/Prover.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
loop_length = "5"
Empty file.