fix arbitrary_from ergonomics by removing the implicit reference in the trait signature

This commit is contained in:
alpaylan 2025-01-13 14:43:12 +03:00
parent 13442808dd
commit 43f6c34408
7 changed files with 57 additions and 59 deletions

View file

@ -13,7 +13,7 @@ pub trait Arbitrary {
}
pub trait ArbitraryFrom<T> {
fn arbitrary_from<R: Rng>(rng: &mut R, t: &T) -> Self;
fn arbitrary_from<R: Rng>(rng: &mut R, t: T) -> Self;
}
pub(crate) fn frequency<

View file

@ -283,10 +283,8 @@ impl InteractionPlan {
}
}
impl InteractionPlan {
// todo: This is a hack to get around the fact that `ArbitraryFrom<T>` can't take a mutable
// reference of T, so instead write a bespoke function without using the trait system.
pub(crate) fn arbitrary_from<R: rand::Rng>(rng: &mut R, env: &mut SimulatorEnv) -> Self {
impl ArbitraryFrom<&mut SimulatorEnv> for InteractionPlan {
fn arbitrary_from<R: rand::Rng>(rng: &mut R, env: &mut SimulatorEnv) -> Self {
let mut plan = InteractionPlan::new();
let num_interactions = env.opts.max_interactions;
@ -304,7 +302,7 @@ impl InteractionPlan {
plan.plan.len(),
num_interactions
);
let interactions = Interactions::arbitrary_from(rng, &(env, plan.stats()));
let interactions = Interactions::arbitrary_from(rng, (env, plan.stats()));
interactions.shadow(env);
plan.plan.push(interactions);
@ -471,7 +469,7 @@ fn random_fault<R: rand::Rng>(_rng: &mut R, _env: &SimulatorEnv) -> Interactions
impl ArbitraryFrom<(&SimulatorEnv, InteractionStats)> for Interactions {
fn arbitrary_from<R: rand::Rng>(
rng: &mut R,
(env, stats): &(&SimulatorEnv, InteractionStats),
(env, stats): (&SimulatorEnv, InteractionStats),
) -> Self {
let remaining_read = ((env.opts.max_interactions as f64 * env.opts.read_percent / 100.0)
- (stats.read_count as f64))
@ -489,7 +487,7 @@ impl ArbitraryFrom<(&SimulatorEnv, InteractionStats)> for Interactions {
(
f64::min(remaining_read, remaining_write) + remaining_create,
Box::new(|rng: &mut R| {
Interactions::Property(Property::arbitrary_from(rng, &(env, stats)))
Interactions::Property(Property::arbitrary_from(rng, (env, &stats)))
}),
),
(

View file

@ -115,10 +115,7 @@ impl Property {
interactions
}
Property::DoubleCreateFailure {
create,
queries,
} => {
Property::DoubleCreateFailure { create, queries } => {
let table_name = create.table.name.clone();
let assumption = Interaction::Assumption(Assertion {
@ -186,7 +183,11 @@ fn remaining(env: &SimulatorEnv, stats: &InteractionStats) -> Remaining {
}
}
fn property_insert_select<R: rand::Rng>(rng: &mut R, env: &SimulatorEnv, remaining: &Remaining) -> Property {
fn property_insert_select<R: rand::Rng>(
rng: &mut R,
env: &SimulatorEnv,
remaining: &Remaining,
) -> Property {
// Get a random table
let table = pick(&env.tables, rng);
// Pick a random column
@ -218,7 +219,7 @@ fn property_insert_select<R: rand::Rng>(rng: &mut R, env: &SimulatorEnv, remaini
// - [ ] The inserted row will not be updated. (todo: add this constraint once UPDATE is implemented)
// - [ ] The table `t` will not be renamed, dropped, or altered. (todo: add this constraint once ALTER or DROP is implemented)
for _ in 0..rng.gen_range(0..3) {
let query = Query::arbitrary_from(rng, &(table, remaining));
let query = Query::arbitrary_from(rng, (table, remaining));
match &query {
Query::Delete(Delete {
table: t,
@ -244,7 +245,7 @@ fn property_insert_select<R: rand::Rng>(rng: &mut R, env: &SimulatorEnv, remaini
// Select the row
let select_query = Select {
table: table.name.clone(),
predicate: Predicate::arbitrary_from(rng, &(table, &row)),
predicate: Predicate::arbitrary_from(rng, (table, &row)),
};
Property::InsertSelect {
@ -254,7 +255,11 @@ fn property_insert_select<R: rand::Rng>(rng: &mut R, env: &SimulatorEnv, remaini
}
}
fn property_double_create_failure<R: rand::Rng>(rng: &mut R, env: &SimulatorEnv, remaining: &Remaining) -> Property {
fn property_double_create_failure<R: rand::Rng>(
rng: &mut R,
env: &SimulatorEnv,
remaining: &Remaining,
) -> Property {
// Get a random table
let table = pick(&env.tables, rng);
// Create the table
@ -268,7 +273,7 @@ fn property_double_create_failure<R: rand::Rng>(rng: &mut R, env: &SimulatorEnv,
// - [x] There will be no errors in the middle interactions.(best effort)
// - [ ] Table `t` will not be renamed or dropped.(todo: add this constraint once ALTER or DROP is implemented)
for _ in 0..rng.gen_range(0..3) {
let query = Query::arbitrary_from(rng, &(table, remaining));
let query = Query::arbitrary_from(rng, (table, remaining));
match &query {
Query::Create(Create { table: t }) => {
// There will be no errors in the middle interactions.
@ -288,12 +293,10 @@ fn property_double_create_failure<R: rand::Rng>(rng: &mut R, env: &SimulatorEnv,
}
}
impl ArbitraryFrom<(&SimulatorEnv, &InteractionStats)> for Property {
fn arbitrary_from<R: rand::Rng>(
rng: &mut R,
(env, stats): &(&SimulatorEnv, &InteractionStats),
(env, stats): (&SimulatorEnv, &InteractionStats),
) -> Self {
let remaining_ = remaining(env, stats);
frequency(

View file

@ -17,7 +17,7 @@ impl Arbitrary for Create {
}
}
impl ArbitraryFrom<Vec<Table>> for Select {
impl ArbitraryFrom<&Vec<Table>> for Select {
fn arbitrary_from<R: Rng>(rng: &mut R, tables: &Vec<Table>) -> Self {
let table = pick(tables, rng);
Self {
@ -27,7 +27,7 @@ impl ArbitraryFrom<Vec<Table>> for Select {
}
}
impl ArbitraryFrom<Vec<&Table>> for Select {
impl ArbitraryFrom<&Vec<&Table>> for Select {
fn arbitrary_from<R: Rng>(rng: &mut R, tables: &Vec<&Table>) -> Self {
let table = pick(tables, rng);
Self {
@ -37,7 +37,7 @@ impl ArbitraryFrom<Vec<&Table>> for Select {
}
}
impl ArbitraryFrom<Table> for Insert {
impl ArbitraryFrom<&Table> for Insert {
fn arbitrary_from<R: Rng>(rng: &mut R, table: &Table) -> Self {
let num_rows = rng.gen_range(1..10);
let values: Vec<Vec<Value>> = (0..num_rows)
@ -56,7 +56,7 @@ impl ArbitraryFrom<Table> for Insert {
}
}
impl ArbitraryFrom<Table> for Delete {
impl ArbitraryFrom<&Table> for Delete {
fn arbitrary_from<R: Rng>(rng: &mut R, table: &Table) -> Self {
Self {
table: table.name.clone(),
@ -65,7 +65,7 @@ impl ArbitraryFrom<Table> for Delete {
}
}
impl ArbitraryFrom<Table> for Query {
impl ArbitraryFrom<&Table> for Query {
fn arbitrary_from<R: Rng>(rng: &mut R, table: &Table) -> Self {
frequency(
vec![
@ -89,7 +89,7 @@ impl ArbitraryFrom<Table> for Query {
}
impl ArbitraryFrom<(&Table, &Remaining)> for Query {
fn arbitrary_from<R: Rng>(rng: &mut R, (table, remaining): &(&Table, &Remaining)) -> Self {
fn arbitrary_from<R: Rng>(rng: &mut R, (table, remaining): (&Table, &Remaining)) -> Self {
frequency(
vec![
(
@ -98,7 +98,7 @@ impl ArbitraryFrom<(&Table, &Remaining)> for Query {
),
(
remaining.read,
Box::new(|rng| Self::Select(Select::arbitrary_from(rng, &vec![*table]))),
Box::new(|rng| Self::Select(Select::arbitrary_from(rng, &vec![table]))),
),
(
remaining.write,
@ -118,7 +118,7 @@ struct CompoundPredicate(Predicate);
struct SimplePredicate(Predicate);
impl ArbitraryFrom<(&Table, bool)> for SimplePredicate {
fn arbitrary_from<R: Rng>(rng: &mut R, (table, predicate_value): &(&Table, bool)) -> Self {
fn arbitrary_from<R: Rng>(rng: &mut R, (table, predicate_value): (&Table, bool)) -> Self {
// Pick a random column
let column_index = rng.gen_range(0..table.columns.len());
let column = &table.columns[column_index];
@ -182,15 +182,15 @@ impl ArbitraryFrom<(&Table, bool)> for SimplePredicate {
}
impl ArbitraryFrom<(&Table, bool)> for CompoundPredicate {
fn arbitrary_from<R: Rng>(rng: &mut R, (table, predicate_value): &(&Table, bool)) -> Self {
fn arbitrary_from<R: Rng>(rng: &mut R, (table, predicate_value): (&Table, bool)) -> Self {
// Decide if you want to create an AND or an OR
Self(if rng.gen_bool(0.7) {
// An AND for true requires each of its children to be true
// An AND for false requires at least one of its children to be false
if *predicate_value {
if predicate_value {
Predicate::And(
(0..rng.gen_range(0..=3))
.map(|_| SimplePredicate::arbitrary_from(rng, &(*table, true)).0)
.map(|_| SimplePredicate::arbitrary_from(rng, (table, true)).0)
.collect(),
)
} else {
@ -209,14 +209,14 @@ impl ArbitraryFrom<(&Table, bool)> for CompoundPredicate {
Predicate::And(
booleans
.iter()
.map(|b| SimplePredicate::arbitrary_from(rng, &(*table, *b)).0)
.map(|b| SimplePredicate::arbitrary_from(rng, (table, *b)).0)
.collect(),
)
}
} else {
// An OR for true requires at least one of its children to be true
// An OR for false requires each of its children to be false
if *predicate_value {
if predicate_value {
// Create a vector of random booleans
let mut booleans = (0..rng.gen_range(0..=3))
.map(|_| rng.gen_bool(0.5))
@ -230,13 +230,13 @@ impl ArbitraryFrom<(&Table, bool)> for CompoundPredicate {
Predicate::Or(
booleans
.iter()
.map(|b| SimplePredicate::arbitrary_from(rng, &(*table, *b)).0)
.map(|b| SimplePredicate::arbitrary_from(rng, (table, *b)).0)
.collect(),
)
} else {
Predicate::Or(
(0..rng.gen_range(0..=3))
.map(|_| SimplePredicate::arbitrary_from(rng, &(*table, false)).0)
.map(|_| SimplePredicate::arbitrary_from(rng, (table, false)).0)
.collect(),
)
}
@ -244,28 +244,28 @@ impl ArbitraryFrom<(&Table, bool)> for CompoundPredicate {
}
}
impl ArbitraryFrom<Table> for Predicate {
impl ArbitraryFrom<&Table> for Predicate {
fn arbitrary_from<R: Rng>(rng: &mut R, table: &Table) -> Self {
let predicate_value = rng.gen_bool(0.5);
CompoundPredicate::arbitrary_from(rng, &(table, predicate_value)).0
CompoundPredicate::arbitrary_from(rng, (table, predicate_value)).0
}
}
impl ArbitraryFrom<(&str, &Value)> for Predicate {
fn arbitrary_from<R: Rng>(rng: &mut R, (column_name, value): &(&str, &Value)) -> Self {
fn arbitrary_from<R: Rng>(rng: &mut R, (column_name, value): (&str, &Value)) -> Self {
one_of(
vec![
Box::new(|_| Predicate::Eq(column_name.to_string(), (*value).clone())),
Box::new(|rng| {
Self::Gt(
column_name.to_string(),
GTValue::arbitrary_from(rng, *value).0,
GTValue::arbitrary_from(rng, value).0,
)
}),
Box::new(|rng| {
Self::Lt(
column_name.to_string(),
LTValue::arbitrary_from(rng, *value).0,
LTValue::arbitrary_from(rng, value).0,
)
}),
],
@ -275,7 +275,7 @@ impl ArbitraryFrom<(&str, &Value)> for Predicate {
}
/// Produces a predicate that is true for the provided row in the given table
fn produce_true_predicate<R: Rng>(rng: &mut R, (t, row): &(&Table, &Vec<Value>)) -> Predicate {
fn produce_true_predicate<R: Rng>(rng: &mut R, (t, row): (&Table, &Vec<Value>)) -> Predicate {
// Pick a column
let column_index = rng.gen_range(0..t.columns.len());
let column = &t.columns[column_index];
@ -304,7 +304,7 @@ fn produce_true_predicate<R: Rng>(rng: &mut R, (t, row): &(&Table, &Vec<Value>))
}
/// Produces a predicate that is false for the provided row in the given table
fn produce_false_predicate<R: Rng>(rng: &mut R, (t, row): &(&Table, &Vec<Value>)) -> Predicate {
fn produce_false_predicate<R: Rng>(rng: &mut R, (t, row): (&Table, &Vec<Value>)) -> Predicate {
// Pick a column
let column_index = rng.gen_range(0..t.columns.len());
let column = &t.columns[column_index];
@ -333,18 +333,18 @@ fn produce_false_predicate<R: Rng>(rng: &mut R, (t, row): &(&Table, &Vec<Value>)
}
impl ArbitraryFrom<(&Table, &Vec<Value>)> for Predicate {
fn arbitrary_from<R: Rng>(rng: &mut R, (t, row): &(&Table, &Vec<Value>)) -> Self {
fn arbitrary_from<R: Rng>(rng: &mut R, (t, row): (&Table, &Vec<Value>)) -> Self {
// We want to produce a predicate that is true for the row
// We can do this by creating several predicates that
// are true, some that are false, combiend them in ways that correspond to the creation of a true predicate
// Produce some true and false predicates
let mut true_predicates = (1..=rng.gen_range(1..=4))
.map(|_| produce_true_predicate(rng, &(*t, row)))
.map(|_| produce_true_predicate(rng, (t, row)))
.collect::<Vec<_>>();
let false_predicates = (0..=rng.gen_range(0..=3))
.map(|_| produce_false_predicate(rng, &(*t, row)))
.map(|_| produce_false_predicate(rng, (t, row)))
.collect::<Vec<_>>();
// Start building a top level predicate from a true predicate

View file

@ -45,7 +45,7 @@ impl Arbitrary for ColumnType {
}
}
impl ArbitraryFrom<Vec<&Value>> for Value {
impl ArbitraryFrom<&Vec<&Value>> for Value {
fn arbitrary_from<R: Rng>(rng: &mut R, values: &Vec<&Self>) -> Self {
if values.is_empty() {
return Self::Null;
@ -55,7 +55,7 @@ impl ArbitraryFrom<Vec<&Value>> for Value {
}
}
impl ArbitraryFrom<ColumnType> for Value {
impl ArbitraryFrom<&ColumnType> for Value {
fn arbitrary_from<R: Rng>(rng: &mut R, column_type: &ColumnType) -> Self {
match column_type {
ColumnType::Integer => Self::Integer(rng.gen_range(i64::MIN..i64::MAX)),
@ -68,7 +68,7 @@ impl ArbitraryFrom<ColumnType> for Value {
pub(crate) struct LTValue(pub(crate) Value);
impl ArbitraryFrom<Vec<&Value>> for LTValue {
impl ArbitraryFrom<&Vec<&Value>> for LTValue {
fn arbitrary_from<R: Rng>(rng: &mut R, values: &Vec<&Value>) -> Self {
if values.is_empty() {
return Self(Value::Null);
@ -79,7 +79,7 @@ impl ArbitraryFrom<Vec<&Value>> for LTValue {
}
}
impl ArbitraryFrom<Value> for LTValue {
impl ArbitraryFrom<&Value> for LTValue {
fn arbitrary_from<R: Rng>(rng: &mut R, value: &Value) -> Self {
match value {
Value::Integer(i) => Self(Value::Integer(rng.gen_range(i64::MIN..*i - 1))),
@ -128,7 +128,7 @@ impl ArbitraryFrom<Value> for LTValue {
pub(crate) struct GTValue(pub(crate) Value);
impl ArbitraryFrom<Vec<&Value>> for GTValue {
impl ArbitraryFrom<&Vec<&Value>> for GTValue {
fn arbitrary_from<R: Rng>(rng: &mut R, values: &Vec<&Value>) -> Self {
if values.is_empty() {
return Self(Value::Null);
@ -139,7 +139,7 @@ impl ArbitraryFrom<Vec<&Value>> for GTValue {
}
}
impl ArbitraryFrom<Value> for GTValue {
impl ArbitraryFrom<&Value> for GTValue {
fn arbitrary_from<R: Rng>(rng: &mut R, value: &Value) -> Self {
match value {
Value::Integer(i) => Self(Value::Integer(rng.gen_range(*i..i64::MAX))),

View file

@ -2,6 +2,7 @@
use clap::Parser;
use core::panic;
use generation::plan::{InteractionPlan, InteractionPlanState};
use generation::ArbitraryFrom;
use limbo_core::Database;
use rand::prelude::*;
use rand_chacha::ChaCha8Rng;

View file

@ -1,5 +1,5 @@
use crate::{
generation::plan::{Interaction, InteractionPlan, Interactions},
generation::plan::{InteractionPlan, Interactions},
runner::execution::Execution,
};
@ -26,13 +26,9 @@ impl InteractionPlan {
for interaction in plan.plan.iter_mut() {
if let Interactions::Property(p) = interaction {
match p {
crate::generation::property::Property::InsertSelect {
queries,
..
} |
crate::generation::property::Property::DoubleCreateFailure {
queries,
..
crate::generation::property::Property::InsertSelect { queries, .. }
| crate::generation::property::Property::DoubleCreateFailure {
queries, ..
} => {
queries.clear();
}