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

code: Replace Option<Value> with bespoke type to better express intent #114

Merged
merged 1 commit into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 3 additions & 3 deletions Code/common/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
Address, Height, Proposal, PublicKey, Round, SignedVote, SigningScheme, Validator,
Address, Height, NilOrVal, Proposal, PublicKey, Round, SignedVote, SigningScheme, Validator,
ValidatorSet, Value, ValueId, Vote,
};

Expand Down Expand Up @@ -42,7 +42,7 @@ where
fn new_prevote(
height: Self::Height,
round: Round,
value_id: Option<ValueId<Self>>,
value_id: NilOrVal<ValueId<Self>>,
address: Self::Address,
) -> Self::Vote;

Expand All @@ -51,7 +51,7 @@ where
fn new_precommit(
height: Self::Height,
round: Round,
value_id: Option<ValueId<Self>>,
value_id: NilOrVal<ValueId<Self>>,
address: Self::Address,
) -> Self::Vote;
}
2 changes: 1 addition & 1 deletion Code/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,5 @@ pub use signed_vote::SignedVote;
pub use signing::SigningScheme;
pub use timeout::{Timeout, TimeoutStep};
pub use validator_set::{Address, Validator, ValidatorSet, VotingPower};
pub use value::Value;
pub use value::{NilOrVal, Value};
pub use vote::{Vote, VoteType};
45 changes: 45 additions & 0 deletions Code/common/src/value.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,50 @@
use core::fmt::Debug;

/// Represents either `Nil` or a value of type `Value`.
///
/// This type is isomorphic to `Option<Value>` but is more explicit about its intent.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum NilOrVal<Value> {
#[default]
Nil,

Val(Value),
}

impl<Value> NilOrVal<Value> {
pub fn is_nil(&self) -> bool {
matches!(self, Self::Nil)
}

pub fn is_val(&self) -> bool {
matches!(self, Self::Val(_))
}

pub fn map<NewValue, F: FnOnce(Value) -> NewValue>(self, f: F) -> NilOrVal<NewValue> {
match self {
NilOrVal::Nil => NilOrVal::Nil,
NilOrVal::Val(value) => NilOrVal::Val(f(value)),
}
}

pub fn as_ref(&self) -> NilOrVal<&Value> {
match self {
NilOrVal::Nil => NilOrVal::Nil,
NilOrVal::Val(value) => NilOrVal::Val(value),
}
}

pub fn value_or_default(self) -> Value
where
Value: Default,
{
match self {
NilOrVal::Nil => Value::default(),
NilOrVal::Val(value) => value,
}
}
}

/// Defines the requirements for the type of value to decide on.
pub trait Value
where
Expand Down
6 changes: 3 additions & 3 deletions Code/common/src/vote.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use core::fmt::Debug;

use crate::{Context, Round, Value};
use crate::{Context, NilOrVal, Round, Value};

/// A type of vote.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -28,10 +28,10 @@ where
fn round(&self) -> Round;

/// Get a reference to the value being voted for.
fn value(&self) -> &Option<<Ctx::Value as Value>::Id>;
fn value(&self) -> &NilOrVal<<Ctx::Value as Value>::Id>;

/// Take ownership of the value being voted for.
fn take_value(self) -> Option<<Ctx::Value as Value>::Id>;
fn take_value(self) -> NilOrVal<<Ctx::Value as Value>::Id>;

/// The type of vote.
fn vote_type(&self) -> VoteType;
Expand Down
6 changes: 3 additions & 3 deletions Code/itf/tests/votekeeper/runner.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::collections::HashMap;

use malachite_common::{Context, Round, Value};
use malachite_common::{Context, NilOrVal, Round, Value};
use malachite_itf::types::{Value as ModelValue, VoteType};
use malachite_itf::votekeeper::VoteKeeperOutput::*;
use malachite_itf::votekeeper::{State, WeightedVote};
Expand Down Expand Up @@ -82,7 +82,7 @@ impl ItfRunner for VoteKeeperRunner {
(Output::PolkaAny, PolkaAny(_expected_round)) => (),
(Output::PolkaValue(value), PolkaValue(_expected_round, expected_value)) => {
assert_eq!(
Some(value),
NilOrVal::Val(value),
value_from_model(&ModelValue::Val(expected_value.to_string())).as_ref()
);
}
Expand All @@ -92,7 +92,7 @@ impl ItfRunner for VoteKeeperRunner {
PrecommitValue(_expected_round, expected_value),
) => {
assert_eq!(
Some(value),
NilOrVal::Val(value),
value_from_model(&ModelValue::Val(expected_value.to_string())).as_ref()
);
}
Expand Down
11 changes: 6 additions & 5 deletions Code/itf/tests/votekeeper/utils.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
use std::collections::HashMap;

use malachite_common::NilOrVal;
use malachite_itf::types::Value;
use malachite_test::{Address, ValueId};

pub const ADDRESSES: [&str; 3] = ["alice", "bob", "john"];

pub fn value_from_model(value: &Value) -> Option<ValueId> {
pub fn value_from_model(value: &Value) -> NilOrVal<ValueId> {
match value {
Value::Nil => None,
Value::Nil => NilOrVal::Nil,
Value::Val(v) => match v.as_str() {
"v1" => Some(1.into()),
"v2" => Some(2.into()),
"v3" => Some(3.into()),
"v1" => NilOrVal::Val(1.into()),
"v2" => NilOrVal::Val(2.into()),
"v3" => NilOrVal::Val(3.into()),
_ => unimplemented!("unknown value {value:?}"),
},
}
Expand Down
6 changes: 3 additions & 3 deletions Code/round/src/output.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use core::fmt;

use malachite_common::{Context, Round, Timeout, TimeoutStep, ValueId};
use malachite_common::{Context, NilOrVal, Round, Timeout, TimeoutStep, ValueId};

use crate::state::RoundValue;

Expand Down Expand Up @@ -29,7 +29,7 @@ impl<Ctx: Context> Output<Ctx> {
pub fn prevote(
height: Ctx::Height,
round: Round,
value_id: Option<ValueId<Ctx>>,
value_id: NilOrVal<ValueId<Ctx>>,
address: Ctx::Address,
) -> Self {
Output::Vote(Ctx::new_prevote(height, round, value_id, address))
Expand All @@ -38,7 +38,7 @@ impl<Ctx: Context> Output<Ctx> {
pub fn precommit(
height: Ctx::Height,
round: Round,
value_id: Option<ValueId<Ctx>>,
value_id: NilOrVal<ValueId<Ctx>>,
address: Ctx::Address,
) -> Self {
Output::Vote(Ctx::new_precommit(height, round, value_id, address))
Expand Down
27 changes: 19 additions & 8 deletions Code/round/src/state_machine.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use malachite_common::{Context, Proposal, Round, TimeoutStep, Value};
use malachite_common::{Context, NilOrVal, Proposal, Round, TimeoutStep, Value};

use crate::input::Input;
use crate::output::Output;
Expand Down Expand Up @@ -259,10 +259,10 @@ where
let vr = proposal.round();
let proposed = proposal.value().id();
let value = match &state.locked {
Some(locked) if locked.round <= vr => Some(proposed), // unlock and prevote
Some(locked) if locked.value.id() == proposed => Some(proposed), // already locked on value
Some(_) => None, // we're locked on a higher round with a different value, prevote nil
None => Some(proposed), // not locked, prevote the value
Some(locked) if locked.round <= vr => NilOrVal::Val(proposed), // unlock and prevote
Some(locked) if locked.value.id() == proposed => NilOrVal::Val(proposed), // already locked on value
Some(_) => NilOrVal::Nil, // we're locked on a higher round with a different value, prevote nil
None => NilOrVal::Val(proposed), // not locked, prevote the value
};

let output = Output::prevote(state.height.clone(), state.round, value, address.clone());
Expand All @@ -276,7 +276,13 @@ pub fn prevote_nil<Ctx>(state: State<Ctx>, address: &Ctx::Address) -> Transition
where
Ctx: Context,
{
let output = Output::prevote(state.height.clone(), state.round, None, address.clone());
let output = Output::prevote(
state.height.clone(),
state.round,
NilOrVal::Nil,
address.clone(),
);

Transition::to(state.with_step(Step::Prevote)).with_output(output)
}

Expand Down Expand Up @@ -306,7 +312,7 @@ where
let output = Output::precommit(
state.height.clone(),
state.round,
Some(value.id()),
NilOrVal::Val(value.id()),
address.clone(),
);

Expand All @@ -325,7 +331,12 @@ pub fn precommit_nil<Ctx>(state: State<Ctx>, address: &Ctx::Address) -> Transiti
where
Ctx: Context,
{
let output = Output::precommit(state.height.clone(), state.round, None, address.clone());
let output = Output::precommit(
state.height.clone(),
state.round,
NilOrVal::Nil,
address.clone(),
);
Transition::to(state.with_step(Step::Precommit)).with_output(output)
}

Expand Down
5 changes: 3 additions & 2 deletions Code/test/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use malachite_common::Context;
use malachite_common::NilOrVal;
use malachite_common::Round;
use malachite_common::SignedVote;

Expand Down Expand Up @@ -50,7 +51,7 @@ impl Context for TestContext {
fn new_prevote(
height: Height,
round: Round,
value_id: Option<ValueId>,
value_id: NilOrVal<ValueId>,
address: Address,
) -> Vote {
Vote::new_prevote(height, round, value_id, address)
Expand All @@ -59,7 +60,7 @@ impl Context for TestContext {
fn new_precommit(
height: Height,
round: Round,
value_id: Option<ValueId>,
value_id: NilOrVal<ValueId>,
address: Address,
) -> Vote {
Vote::new_precommit(height, round, value_id, address)
Expand Down
28 changes: 19 additions & 9 deletions Code/test/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use rand::rngs::StdRng;
use rand::SeedableRng;

use malachite_common::{Round, Timeout, VotingPower};
use malachite_common::{NilOrVal, Round, Timeout, VotingPower};
use malachite_driver::{Input, Output, ProposerSelector, Validity};
use malachite_round::state::{RoundValue, State, Step};

Expand Down Expand Up @@ -87,7 +87,7 @@ pub fn prevote_output(
let value = Value::new(9999);

Some(Output::Vote(
Vote::new_prevote(Height::new(1), round, Some(value.id()), *addr).signed(sk),
Vote::new_prevote(Height::new(1), round, NilOrVal::Val(value.id()), *addr).signed(sk),
))
}

Expand All @@ -97,26 +97,34 @@ pub fn prevote_nil_output(
sk: &PrivateKey,
) -> Option<Output<TestContext>> {
Some(Output::Vote(
Vote::new_prevote(Height::new(1), round, None, *addr).signed(sk),
Vote::new_prevote(Height::new(1), round, NilOrVal::Nil, *addr).signed(sk),
))
}

pub fn prevote_input(addr: &Address, sk: &PrivateKey) -> Input<TestContext> {
let value = Value::new(9999);

Input::Vote(
Vote::new_prevote(Height::new(1), Round::new(0), Some(value.id()), *addr).signed(sk),
Vote::new_prevote(
Height::new(1),
Round::new(0),
NilOrVal::Val(value.id()),
*addr,
)
.signed(sk),
)
}

pub fn prevote_nil_input(addr: &Address, sk: &PrivateKey) -> Input<TestContext> {
Input::Vote(Vote::new_prevote(Height::new(1), Round::new(0), None, *addr).signed(sk))
Input::Vote(Vote::new_prevote(Height::new(1), Round::new(0), NilOrVal::Nil, *addr).signed(sk))
}

pub fn prevote_input_at(round: Round, addr: &Address, sk: &PrivateKey) -> Input<TestContext> {
let value = Value::new(9999);

Input::Vote(Vote::new_prevote(Height::new(1), round, Some(value.id()), *addr).signed(sk))
Input::Vote(
Vote::new_prevote(Height::new(1), round, NilOrVal::Val(value.id()), *addr).signed(sk),
)
}

pub fn precommit_output(
Expand All @@ -126,7 +134,7 @@ pub fn precommit_output(
sk: &PrivateKey,
) -> Option<Output<TestContext>> {
Some(Output::Vote(
Vote::new_precommit(Height::new(1), round, Some(value.id()), *addr).signed(sk),
Vote::new_precommit(Height::new(1), round, NilOrVal::Val(value.id()), *addr).signed(sk),
))
}

Expand All @@ -136,7 +144,7 @@ pub fn precommit_nil_output(
sk: &PrivateKey,
) -> Option<Output<TestContext>> {
Some(Output::Vote(
Vote::new_precommit(Height::new(1), round, None, *addr).signed(sk),
Vote::new_precommit(Height::new(1), round, NilOrVal::Nil, *addr).signed(sk),
))
}

Expand All @@ -146,7 +154,9 @@ pub fn precommit_input(
addr: &Address,
sk: &PrivateKey,
) -> Input<TestContext> {
Input::Vote(Vote::new_precommit(Height::new(1), round, Some(value.id()), *addr).signed(sk))
Input::Vote(
Vote::new_precommit(Height::new(1), round, NilOrVal::Val(value.id()), *addr).signed(sk),
)
}

pub fn decide_output(round: Round, value: Value) -> Option<Output<TestContext>> {
Expand Down
Loading
Loading