From ca60656871162e94809921026ec191d2608b0874 Mon Sep 17 00:00:00 2001 From: Neven Villani Date: Thu, 7 Sep 2023 22:20:14 +0200 Subject: [PATCH] more lazyness, less heavy on the memory --- src/borrow_tracker/tree_borrows/exhaustive.rs | 95 +++++--------- src/borrow_tracker/tree_borrows/perms.rs | 24 ++-- src/borrow_tracker/tree_borrows/tree.rs | 118 +++++++++--------- 3 files changed, 101 insertions(+), 136 deletions(-) diff --git a/src/borrow_tracker/tree_borrows/exhaustive.rs b/src/borrow_tracker/tree_borrows/exhaustive.rs index affd503a04..d4ab468337 100644 --- a/src/borrow_tracker/tree_borrows/exhaustive.rs +++ b/src/borrow_tracker/tree_borrows/exhaustive.rs @@ -5,7 +5,7 @@ #![cfg(test)] pub trait Exhaustive: Sized { - fn exhaustive() -> Vec; + fn exhaustive() -> Box>; } macro_rules! precondition { @@ -18,8 +18,8 @@ macro_rules! precondition { pub(crate) use precondition; impl Exhaustive for bool { - fn exhaustive() -> Vec { - vec![true, false] + fn exhaustive() -> Box> { + Box::new(vec![true, false].into_iter()) } } @@ -27,102 +27,71 @@ impl Exhaustive for bool { impl Exhaustive for Option where - T: Exhaustive, + T: Exhaustive + 'static, { - fn exhaustive() -> Vec { - let mut v = vec![None]; - for t in T::exhaustive() { - v.push(Some(t)); - } - v + fn exhaustive() -> Box> { + Box::new(std::iter::once(None).chain(T::exhaustive().map(Some))) } } impl Exhaustive for (T1, T2) where - T1: Exhaustive + Clone, - T2: Exhaustive, + T1: Exhaustive + Clone + 'static, + T2: Exhaustive + 'static, { - fn exhaustive() -> Vec { - let mut v = Vec::new(); - for t1 in T1::exhaustive() { - for t2 in T2::exhaustive() { - v.push((t1.clone(), t2)); - } - } - v + fn exhaustive() -> Box> { + Box::new(T1::exhaustive().flat_map(|t1| T2::exhaustive().map(move |t2| (t1.clone(), t2)))) } } impl Exhaustive for [T; 1] where - T: Exhaustive, + T: Exhaustive + 'static, { - fn exhaustive() -> Vec { - let mut v = Vec::new(); - for t1 in T::exhaustive() { - v.push([t1]); - } - v + fn exhaustive() -> Box> { + Box::new(T::exhaustive().map(|t| [t])) } } impl Exhaustive for [T; 2] where - T: Exhaustive + Clone, + T: Exhaustive + Clone + 'static, { - fn exhaustive() -> Vec { - let mut v = Vec::new(); - for t1 in T::exhaustive() { - for t2 in T::exhaustive() { - v.push([t1.clone(), t2]); - } - } - v + fn exhaustive() -> Box> { + Box::new(T::exhaustive().flat_map(|t1| T::exhaustive().map(move |t2| [t1.clone(), t2]))) } } impl Exhaustive for [T; 3] where - T: Exhaustive + Clone, + T: Exhaustive + Clone + 'static, { - fn exhaustive() -> Vec { - let mut v = Vec::new(); - for [t1, t2] in <[T; 2]>::exhaustive() { - for t3 in T::exhaustive() { - v.push([t1.clone(), t2.clone(), t3]); - } - } - v + fn exhaustive() -> Box> { + Box::new( + <[T; 2]>::exhaustive() + .flat_map(|[t1, t2]| T::exhaustive().map(move |t3| [t1.clone(), t2.clone(), t3])), + ) } } impl Exhaustive for [T; 4] where - T: Exhaustive + Clone, + T: Exhaustive + Clone + 'static, { - fn exhaustive() -> Vec { - let mut v = Vec::new(); - for [t1, t2] in <[T; 2]>::exhaustive() { - for [t3, t4] in <[T; 2]>::exhaustive() { - v.push([t1.clone(), t2.clone(), t3, t4]); - } - } - v + fn exhaustive() -> Box> { + Box::new(<[T; 2]>::exhaustive().flat_map(|[t1, t2]| { + <[T; 2]>::exhaustive().map(move |[t3, t4]| [t1.clone(), t2.clone(), t3, t4]) + })) } } impl Exhaustive for [T; 5] where - T: Exhaustive + Clone, + T: Exhaustive + Clone + 'static, { - fn exhaustive() -> Vec { - let mut v = Vec::new(); - for [t1, t2] in <[T; 2]>::exhaustive() { - for [t3, t4, t5] in <[T; 3]>::exhaustive() { - v.push([t1.clone(), t2.clone(), t3, t4, t5]); - } - } - v + fn exhaustive() -> Box> { + Box::new(<[T; 2]>::exhaustive().flat_map(|[t1, t2]| { + <[T; 3]>::exhaustive().map(move |[t3, t4, t5]| [t1.clone(), t2.clone(), t3, t4, t5]) + })) } } diff --git a/src/borrow_tracker/tree_borrows/perms.rs b/src/borrow_tracker/tree_borrows/perms.rs index 87cf59f08f..4e00dad23f 100644 --- a/src/borrow_tracker/tree_borrows/perms.rs +++ b/src/borrow_tracker/tree_borrows/perms.rs @@ -410,32 +410,32 @@ mod propagation_optimization_checks { use crate::borrow_tracker::tree_borrows::exhaustive::{precondition, Exhaustive}; impl Exhaustive for PermissionPriv { - fn exhaustive() -> Vec { - let mut v = vec![Active, Frozen, Disabled]; - for ty_is_freeze in bool::exhaustive() { - v.push(Reserved { ty_is_freeze }); - } - v + fn exhaustive() -> Box> { + Box::new( + vec![Active, Frozen, Disabled] + .into_iter() + .chain(bool::exhaustive().map(|ty_is_freeze| Reserved { ty_is_freeze })), + ) } } impl Exhaustive for Permission { - fn exhaustive() -> Vec { - PermissionPriv::exhaustive().into_iter().map(|inner| Self { inner }).collect() + fn exhaustive() -> Box> { + Box::new(PermissionPriv::exhaustive().map(|inner| Self { inner })) } } impl Exhaustive for AccessKind { - fn exhaustive() -> Vec { + fn exhaustive() -> Box> { use AccessKind::*; - vec![Read, Write] + Box::new(vec![Read, Write].into_iter()) } } impl Exhaustive for AccessRelatedness { - fn exhaustive() -> Vec { + fn exhaustive() -> Box> { use AccessRelatedness::*; - vec![This, StrictChildAccess, AncestorAccess, DistantAccess] + Box::new(vec![This, StrictChildAccess, AncestorAccess, DistantAccess].into_iter()) } } diff --git a/src/borrow_tracker/tree_borrows/tree.rs b/src/borrow_tracker/tree_borrows/tree.rs index 05d55b0298..c469e96628 100644 --- a/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/borrow_tracker/tree_borrows/tree.rs @@ -685,13 +685,11 @@ mod commutation_tests { use std::fmt; impl Exhaustive for LocationState { - fn exhaustive() -> Vec { + fn exhaustive() -> Box> { // We keep `latest_foreign_access` at `None` as that's just a cache. - let mut v = Vec::new(); - for (permission, initialized) in <(Permission, bool)>::exhaustive() { - v.push(Self { permission, initialized, latest_foreign_access: None }); - } - v + Box::new(<(Permission, bool)>::exhaustive().map(|(permission, initialized)| { + Self { permission, initialized, latest_foreign_access: None } + })) } } @@ -769,9 +767,9 @@ mod commutation_tests { } impl Exhaustive for AccessRel2 { - fn exhaustive() -> Vec { + fn exhaustive() -> Box> { use AccessRel2 as Rel; - vec![Rel::ChildX, Rel::ChildY, Rel::Other] + Box::new(vec![Rel::ChildX, Rel::ChildY, Rel::Other].into_iter()) } } @@ -782,11 +780,10 @@ mod commutation_tests { } impl Exhaustive for Access2 { - fn exhaustive() -> Vec { - <(AccessRel2, AccessKind)>::exhaustive() - .into_iter() - .map(|(rel2, kind)| Access2 { rel2, kind }) - .collect() + fn exhaustive() -> Box> { + Box::new( + <(AccessRel2, AccessKind)>::exhaustive().map(|(rel2, kind)| Access2 { rel2, kind }), + ) } } @@ -815,14 +812,10 @@ mod commutation_tests { } impl Exhaustive for LocStateProt { - fn exhaustive() -> Vec { - let mut v = Vec::new(); - for state in LocationState::exhaustive() { - for prot in bool::exhaustive() { - v.push(Self { state, prot }); - } - } - v + fn exhaustive() -> Box> { + Box::new( + <(LocationState, bool)>::exhaustive().map(|(state, prot)| Self { state, prot }), + ) } } @@ -885,12 +878,8 @@ mod commutation_tests { } impl Exhaustive for LocStateProt2 { - fn exhaustive() -> Vec { - let mut v = Vec::new(); - for [x, y] in <[LocStateProt; 2]>::exhaustive() { - v.push(Self { x, y }); - } - v + fn exhaustive() -> Box> { + Box::new(<[LocStateProt; 2]>::exhaustive().map(|[x, y]| Self { x, y })) } } @@ -907,15 +896,15 @@ mod commutation_tests { } impl Opaque2 { - fn exhaustive_witness() -> Vec { - <[Option; 5]>::exhaustive() - .into_iter() - .map(|x| Opaque2 { events: x.into_iter().collect() }) - .collect() + fn exhaustive_witness() -> Box> { + Box::new( + <[Option; 5]>::exhaustive() + .map(|x| Opaque2 { events: x.into_iter().collect() }), + ) } } impl Exhaustive for Opaque2 { - fn exhaustive() -> Vec { + fn exhaustive() -> Box> { // There are a lot of combinations (infinitely many in fact), // so we're only generating a small subset and then testing through other means // that we have a representative sample. @@ -924,35 +913,42 @@ mod commutation_tests { // - since accesses are idempotent it's never useful to have the same twice in a row // - sequences of length 3 or less might as well have their noops at the end // This reduces by a lot the space to explore. - let mut v = Vec::new(); - for acc0 in >::exhaustive() { - for acc1 in >::exhaustive() { - precondition!(acc0.is_none() || acc1.is_some()); - precondition!(if let (Some(acc0), Some(acc1)) = (acc0, acc1) { - acc0.rel2 != acc1.rel2 - } else { - true - }); - for acc2 in >::exhaustive() { - precondition!(acc1.is_none() || acc2.is_some()); - precondition!(if let (Some(acc1), Some(acc2)) = (acc1, acc2) { - acc1.rel2 != acc2.rel2 + Box::new( + <[Option; 2]>::exhaustive() + .filter(|[acc0, acc1]| acc0.is_none() || acc1.is_some()) + .filter(|[acc0, acc1]| { + if let (Some(acc0), Some(acc1)) = (acc0, acc1) { + acc0.rel2 != acc1.rel2 } else { true - }); - for acc3 in >::exhaustive() { - precondition!(acc2.is_none() || acc3.is_some()); - precondition!(if let (Some(acc2), Some(acc3)) = (acc2, acc3) { - acc2.rel2 != acc3.rel2 - } else { - true - }); - v.push(Opaque2 { events: vec![acc0, acc1, acc2, acc3] }) } - } - } - } - v + }) + .flat_map(|[acc0, acc1]| { + >::exhaustive() + .filter(move |acc2| acc1.is_none() || acc2.is_some()) + .filter(move |acc2| { + if let (Some(acc1), Some(acc2)) = (acc1, acc2) { + acc1.rel2 != acc2.rel2 + } else { + true + } + }) + .flat_map(move |acc2| { + >::exhaustive() + .filter(move |acc3| acc2.is_none() || acc3.is_some()) + .filter(move |acc3| { + if let (Some(acc2), Some(acc3)) = (acc2, acc3) { + acc2.rel2 != acc3.rel2 + } else { + true + } + }) + .map(move |acc3| { + Opaque2 { events: vec![acc0, acc1, acc2, acc3] } + }) + }) + }), + ) } } @@ -1108,7 +1104,7 @@ mod commutation_tests { } impl Exhaustive for Pattern { - fn exhaustive() -> Vec { + fn exhaustive() -> Box> { let mut v = Vec::new(); for (x_initial_state, y_initial_state) in <(LocationState, LocationState)>::exhaustive() @@ -1134,7 +1130,7 @@ mod commutation_tests { } } } - v + Box::new(v.into_iter()) } }