radicle: force new or initial construction of LWWReg
Using LWWReg::from will always set the clock value to the default, which can end up being used wrong. Instead, introduce a constructor method `initial` to indicate that it should be used on initial construction, while `new` should be used for newer values of the register. Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com> X-Clacks-Overhead: GNU Terry Pratchett
This commit is contained in:
parent
6417a71e08
commit
8404b5925d
|
|
@ -14,6 +14,16 @@ pub struct LWWReg<T, C = clock::Lamport> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Semilattice, C: PartialOrd> LWWReg<T, C> {
|
impl<T: Semilattice, C: PartialOrd> LWWReg<T, C> {
|
||||||
|
pub fn initial(value: T) -> Self
|
||||||
|
where
|
||||||
|
C: Default,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
clock: Max::from(C::default()),
|
||||||
|
value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new(value: T, clock: C) -> Self {
|
pub fn new(value: T, clock: C) -> Self {
|
||||||
Self {
|
Self {
|
||||||
clock: Max::from(clock),
|
clock: Max::from(clock),
|
||||||
|
|
@ -46,15 +56,6 @@ impl<T: Semilattice, C: PartialOrd> LWWReg<T, C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, C: Default> From<T> for LWWReg<T, C> {
|
|
||||||
fn from(value: T) -> Self {
|
|
||||||
Self {
|
|
||||||
clock: Max::from(C::default()),
|
|
||||||
value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Default, C: Default + Bounded> Default for LWWReg<T, C> {
|
impl<T: Default, C: Default + Bounded> Default for LWWReg<T, C> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
|
||||||
|
|
@ -167,9 +167,9 @@ impl Semilattice for Proposal {
|
||||||
impl Default for Proposal {
|
impl Default for Proposal {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
title: Max::from(String::default()).into(),
|
title: LWWReg::initial(Max::from(String::default())),
|
||||||
description: Max::from(String::default()).into(),
|
description: LWWReg::initial(Max::from(String::default())),
|
||||||
state: Max::from(State::default()).into(),
|
state: LWWReg::initial(Max::from(State::default())),
|
||||||
revisions: GMap::default(),
|
revisions: GMap::default(),
|
||||||
timeline: GSet::default(),
|
timeline: GSet::default(),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,9 +83,9 @@ pub struct Issue {
|
||||||
/// Actors assigned to this issue.
|
/// Actors assigned to this issue.
|
||||||
assignees: LWWSet<ActorId>,
|
assignees: LWWSet<ActorId>,
|
||||||
/// Title of the issue.
|
/// Title of the issue.
|
||||||
title: LWWReg<Max<String>, clock::Lamport>,
|
title: LWWReg<Max<String>>,
|
||||||
/// Current state of the issue.
|
/// Current state of the issue.
|
||||||
state: LWWReg<Max<State>, clock::Lamport>,
|
state: LWWReg<Max<State>>,
|
||||||
/// Associated tags.
|
/// Associated tags.
|
||||||
tags: LWWSet<Tag>,
|
tags: LWWSet<Tag>,
|
||||||
/// Discussion around this issue.
|
/// Discussion around this issue.
|
||||||
|
|
@ -106,8 +106,8 @@ impl Default for Issue {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
assignees: LWWSet::default(),
|
assignees: LWWSet::default(),
|
||||||
title: Max::from(String::default()).into(),
|
title: LWWReg::initial(Max::from(String::default())),
|
||||||
state: Max::from(State::default()).into(),
|
state: LWWReg::initial(Max::from(State::default())),
|
||||||
tags: LWWSet::default(),
|
tags: LWWSet::default(),
|
||||||
thread: Thread::default(),
|
thread: Thread::default(),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -160,10 +160,10 @@ impl Semilattice for Patch {
|
||||||
impl Default for Patch {
|
impl Default for Patch {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
title: Max::from(String::default()).into(),
|
title: LWWReg::initial(Max::from(String::default())),
|
||||||
description: Max::from(String::default()).into(),
|
description: LWWReg::initial(Max::from(String::default())),
|
||||||
state: Max::from(State::default()).into(),
|
state: LWWReg::initial(Max::from(State::default())),
|
||||||
target: Max::from(MergeTarget::default()).into(),
|
target: LWWReg::initial(Max::from(MergeTarget::default())),
|
||||||
tags: LWWSet::default(),
|
tags: LWWSet::default(),
|
||||||
revisions: GMap::default(),
|
revisions: GMap::default(),
|
||||||
timeline: GSet::default(),
|
timeline: GSet::default(),
|
||||||
|
|
@ -326,6 +326,7 @@ impl store::FromHistory for Patch {
|
||||||
base,
|
base,
|
||||||
oid,
|
oid,
|
||||||
timestamp,
|
timestamp,
|
||||||
|
op.clock,
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -417,10 +418,11 @@ impl Revision {
|
||||||
base: git::Oid,
|
base: git::Oid,
|
||||||
oid: git::Oid,
|
oid: git::Oid,
|
||||||
timestamp: Timestamp,
|
timestamp: Timestamp,
|
||||||
|
clock: Clock,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
author,
|
author,
|
||||||
description: LWWReg::from(Max::from(description)),
|
description: LWWReg::new(Max::from(description), clock),
|
||||||
base,
|
base,
|
||||||
oid,
|
oid,
|
||||||
discussion: Thread::default(),
|
discussion: Thread::default(),
|
||||||
|
|
@ -1053,6 +1055,7 @@ impl<'a> Patches<'a> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use std::path::Path;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::{array, iter};
|
use std::{array, iter};
|
||||||
|
|
||||||
|
|
@ -1460,6 +1463,7 @@ mod test {
|
||||||
let (_, signer, project) = test::setup::context(&tmp);
|
let (_, signer, project) = test::setup::context(&tmp);
|
||||||
let base = git::Oid::from_str("cb18e95ada2bb38aadd8e6cef0963ce37a87add3").unwrap();
|
let base = git::Oid::from_str("cb18e95ada2bb38aadd8e6cef0963ce37a87add3").unwrap();
|
||||||
let oid = git::Oid::from_str("518d5069f94c03427f694bb494ac1cd7d1339380").unwrap();
|
let oid = git::Oid::from_str("518d5069f94c03427f694bb494ac1cd7d1339380").unwrap();
|
||||||
|
let blob = git::Oid::from_str("518d5069f94c03427f694bb494ac1cd7d133999").unwrap();
|
||||||
let mut patches = Patches::open(&project).unwrap();
|
let mut patches = Patches::open(&project).unwrap();
|
||||||
let mut patch = patches
|
let mut patch = patches
|
||||||
.create(
|
.create(
|
||||||
|
|
@ -1476,17 +1480,33 @@ mod test {
|
||||||
let (rid, _) = patch.latest().unwrap();
|
let (rid, _) = patch.latest().unwrap();
|
||||||
let rid = *rid;
|
let rid = *rid;
|
||||||
|
|
||||||
|
let inline = vec![CodeComment {
|
||||||
|
location: CodeLocation {
|
||||||
|
blob,
|
||||||
|
path: Path::new("file.rs").to_path_buf(),
|
||||||
|
commit: oid,
|
||||||
|
lines: 1..3,
|
||||||
|
},
|
||||||
|
comment: "Nice!".to_owned(),
|
||||||
|
timestamp: Timestamp::new(0),
|
||||||
|
}];
|
||||||
patch
|
patch
|
||||||
.review(
|
.review(
|
||||||
rid,
|
rid,
|
||||||
Some(Verdict::Accept),
|
Some(Verdict::Accept),
|
||||||
Some("LGTM".to_owned()),
|
Some("LGTM".to_owned()),
|
||||||
vec![],
|
inline.clone(),
|
||||||
&signer,
|
&signer,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
patch
|
patch
|
||||||
.review(rid, Some(Verdict::Reject), None, vec![], &signer)
|
.review(
|
||||||
|
rid,
|
||||||
|
Some(Verdict::Reject),
|
||||||
|
Some("LGTM".to_owned()),
|
||||||
|
vec![],
|
||||||
|
&signer,
|
||||||
|
)
|
||||||
.unwrap(); // Overwrite the verdict.
|
.unwrap(); // Overwrite the verdict.
|
||||||
|
|
||||||
let id = patch.id;
|
let id = patch.id;
|
||||||
|
|
@ -1496,15 +1516,23 @@ mod test {
|
||||||
|
|
||||||
let review = revision.reviews.get(signer.public_key()).unwrap();
|
let review = revision.reviews.get(signer.public_key()).unwrap();
|
||||||
assert_eq!(review.verdict(), Some(Verdict::Reject));
|
assert_eq!(review.verdict(), Some(Verdict::Reject));
|
||||||
assert_eq!(review.comment(), None);
|
assert_eq!(review.comment(), Some("LGTM"));
|
||||||
|
assert_eq!(review.inline().cloned().collect::<Vec<_>>(), inline);
|
||||||
|
|
||||||
patch
|
patch
|
||||||
.review(rid, None, Some("Whoops!".to_owned()), vec![], &signer)
|
.review(
|
||||||
|
rid,
|
||||||
|
Some(Verdict::Reject),
|
||||||
|
Some("Whoops!".to_owned()),
|
||||||
|
vec![],
|
||||||
|
&signer,
|
||||||
|
)
|
||||||
.unwrap(); // Overwrite the comment.
|
.unwrap(); // Overwrite the comment.
|
||||||
let (_, revision) = patch.latest().unwrap();
|
let (_, revision) = patch.latest().unwrap();
|
||||||
let review = revision.reviews.get(signer.public_key()).unwrap();
|
let review = revision.reviews.get(signer.public_key()).unwrap();
|
||||||
assert_eq!(review.verdict(), None);
|
assert_eq!(review.verdict(), Some(Verdict::Reject));
|
||||||
assert_eq!(review.comment(), Some("Whoops!"));
|
assert_eq!(review.comment(), Some("Whoops!"));
|
||||||
|
assert_eq!(review.inline().cloned().collect::<Vec<_>>(), inline);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue