Struct bellframe::row::Row[][src]

pub struct Row { /* fields omitted */ }
Expand description

A single Row of Bells.

This can be viewed as a permutation of rounds on a given Stage.

A Row must always be valid according to the Framework - i.e., it must contain every Bell up to its Stage once and precisely once. This is only checked in the constructors and then used as assumed knowledge to avoid further checks. This is similar to how &str and String are required to be valid UTF-8.

Example

use proj_core::{Bell, Row, Stage, InvalidRowError};

// Create rounds on 8 bells.  Rounds is always valid on any `Stage`
let rounds_on_8 = Row::rounds(Stage::MAJOR);
assert_eq!(rounds_on_8.stage(), Stage::MAJOR);
assert_eq!(rounds_on_8.to_string(), "12345678");

// Parse a generic (valid) change from a string.  Note how invalid
// `char`s are skipped.  This could fail if the resulting `Row` is
// invalid, so we use ? to propogate that error out of the current
// function.
let queens = Row::parse("13579 | 24680")?;
assert_eq!(queens.stage(), Stage::ROYAL);
assert_eq!(queens.to_string(), "1357924680");

// If we try to parse an invalid `Row`, we get an error.  This means
// that we can assume that all `Row`s satisfy the Framework's definition
assert_eq!(
    Row::parse("112345"),
    Err(InvalidRowError::DuplicateBell(Bell::from_name('1').unwrap()))
);

Implementations

Creates a Row from a Vec of Bells, checking that the the resulting Row is valid.

Example

use proj_core::{Bell, InvalidRowError, Row};

// Converting a `Row` from a valid `Vec` of `Bell`s is fine
assert_eq!(
    Row::from_vec(vec![
        Bell::from_name('4').unwrap(),
        Bell::from_name('2').unwrap(),
        Bell::from_name('1').unwrap(),
        Bell::from_name('3').unwrap(),
    ])?.to_string(),
    "4213"
);
// Converting a `Row` from an invalid `Vec` of `Bell`s is not so fine
assert_eq!(
    Row::from_vec(vec![
        Bell::from_name('4').unwrap(),
        Bell::from_name('2').unwrap(),
        Bell::from_name('1').unwrap(),
        Bell::from_name('4').unwrap(),
    ]),
    Err(InvalidRowError::DuplicateBell(Bell::from_name('4').unwrap()))
);

Creates a Row from a Vec of Bells, without checking that the the resulting Row is valid. Only use this if you’re certain that the input is valid, since performing invalid operations on Rows is undefined behaviour.

Safety

This function is safe if bells corresponds to a valid Row according to the CC’s Framework. This means that each Bell is unique, and has index smaller than the bells.len().

Example

use proj_core::{Bell, InvalidRowError, Row};

// Converting a `Row` from a valid `Vec` of `Bell`s is fine, but still unsafe
assert_eq!(
    unsafe {
        Row::from_vec_unchecked(vec![
            Bell::from_name('4')?,
            Bell::from_name('2')?,
            Bell::from_name('1')?,
            Bell::from_name('3')?,
        ])
    }.to_string(),
    "4213"
);
// Converting a `Row` from an invalid `Vec` of `Bell`s compiles and runs,
// but silently creates an invalid `Row`
assert_eq!(
    unsafe {
        Row::from_vec_unchecked(vec![
            Bell::from_name('4')?,
            Bell::from_name('2')?,
            Bell::from_name('1')?,
            Bell::from_name('4')?,
        ])
    }.to_string(),
    "4214"
);

Utility function that creates a Row from an iterator of Bells, without performing the validity check. This function is unsafe; only use it if you can guarantee that the resulting Row is valid.

Safety

This function is safe if iter yields a valid Row according to the CC’s Framework. This means that each Bell is unique, and has index smaller than the number of items yeilded by iter.

Example

use proj_core::{Bell, Row, Stage, InvalidRowError};

// Create a valid row from an iterator over `Bell`s
let iter = [0, 3, 4, 2, 1].iter().copied().map(Bell::from_index);
let row = unsafe { Row::from_iter_unchecked(iter) };
assert_eq!(row.to_string(), "14532");
// Create an invalid row from an iterator over `Bell`s.  We get no error,
// but doing anything with the resulting `Row` is undefined behaviour
let iter = [0, 3, 7, 2, 1].iter().copied().map(Bell::from_index);
let row = unsafe { Row::from_iter_unchecked(iter) };
assert_eq!(row.to_string(), "14832");

Returns the Stage of this Row.

Example

use proj_core::{Row, Stage};

// Rounds on a given `Stage` should have that `Stage`
assert_eq!(Row::rounds(Stage::MINIMUS).stage(), Stage::MINIMUS);
assert_eq!(Row::rounds(Stage::SEPTUPLES).stage(), Stage::SEPTUPLES);

assert_eq!(Row::parse("41325")?.stage(), Stage::DOUBLES);
assert_eq!(Row::parse("321 654 987 0")?.stage(), Stage::ROYAL);

Multiply two Rows (i.e. use the RHS to permute the LHS), but without checking that the Stages are compatible. This is slighlty faster than using * or Row::mul, but is unsafe: the output is not guaruteed to be valid unless both inputs have the same Stage.

Safety

This is safe if the two Rows have the same Stage (which is often an invariant enforced by other datatypes, such as Block).

Example

use proj_core::{Bell, Row, Stage, IncompatibleStages};

// Multiplying two Rows of the same Stage is OK, but still unsafe
assert_eq!(
    unsafe {
        Row::parse("13425678")?.mul_unchecked(&Row::parse("43217568")?)
    },
    Row::parse("24317568")?
);
// Multiplying two Rows of different Stages is not OK, and creates an invalid Row.
// Note how both sides of the `assert_eq` have to use unsafe to create an invalid Row.
assert_eq!(
    unsafe { Row::parse("13475628")?.mul_unchecked(&Row::parse("4321")?) },
    unsafe {Row::from_vec_unchecked(
        [7, 4, 3, 1].iter().map(|&x| Bell::from_number(x).unwrap()).collect()
    )}
);

Multiply two Rows (i.e. use the RHS to permute the LHS), storing the result in an existing Row (thus making use of its allocation).

Safety

This is safe if self and rhs both have the same Stage.

Find the inverse of a Row. If X is the input Row, and Y = !X, then XY = YX = I where I is the identity on the same stage as X (i.e. rounds). This operation cannot fail, since valid Rows are guaruteed to have an inverse.

Example

use proj_core::{Row, Stage};

// The inverse of Queens is Tittums
assert_eq!(!Row::parse("135246")?, Row::parse("142536")?);
// Backrounds is self-inverse
assert_eq!(!Row::backrounds(Stage::MAJOR), Row::backrounds(Stage::MAJOR));
// `1324` inverts to `1423`
assert_eq!(!Row::parse("1342")?, Row::parse("1423")?);

Calculate the inverse of this Row, storing the result in an existing Row (thus making use of its allocation). This resizes out to make it the right Stage to take the output value.

Example

use proj_core::{Row, Stage};

// Create a new row that will be overwritten to avoid reallocations
let mut row_buf = Row::empty();
// The inverse of Queens is Tittums
Row::parse("135246")?.inv_into(&mut row_buf);
assert_eq!(row_buf, Row::parse("142536")?);
// Backrounds is self-inverse
Row::backrounds(Stage::MAJOR).inv_into(&mut row_buf);
assert_eq!(row_buf, Row::backrounds(Stage::MAJOR));
// `1324` inverts to `1423`
Row::parse("1342")?.inv_into(&mut row_buf);
assert_eq!(row_buf, Row::parse("1423")?);

Swap two Bells round in this Row, panicking if either of the indices point out of bounds.

Example

use proj_core::{Row, Stage};

let mut rounds = Row::rounds(Stage::MAJOR);
assert_eq!(rounds.to_string(), "12345678");
rounds.swap(0, 1); // Note we are using 0-indexing
assert_eq!(rounds.to_string(), "21345678");
rounds.swap(2, 5); // Note we are using 0-indexing
assert_eq!(rounds.to_string(), "21645378");

Extend this Row in-place with cover bells so that it has a given Stage

Parse a string into a Row, skipping any chars that aren’t valid bell names. This returns Err(InvalidRowError) if the Row would be invalid.

Example

use proj_core::{Bell, Row, Stage, InvalidRowError};

// Parsing a valid Row is fine
assert_eq!(Row::parse("12543")?.to_string(), "12543");
// Parsing valid rows with invalid characters is also fine
assert_eq!(Row::parse("4321\t[65 78]")?.to_string(), "43216578");
assert_eq!(Row::parse("3|2|1  6|5|4  9|8|7")?.to_string(), "321654987");
// Parsing an invalid `Row` returns an error describing the problem
assert_eq!(
    Row::parse("112345"),
    Err(InvalidRowError::DuplicateBell(Bell::from_number(1).unwrap()))
);
assert_eq!(
    Row::parse("12745"),
    Err(InvalidRowError::BellOutOfStage(
        Bell::from_number(7).unwrap(),
        Stage::DOUBLES
    ))
);

Parse a string into a Row, extending to the given Stage if required and skipping any chars that aren’t valid bell names. This returns Err(InvalidRowError) if the Row would be invalid, and this will produce better error messages than Row::parse because of the extra information provided by the Stage.

Example

use proj_core::{Bell, Row, Stage, InvalidRowError};

// Parsing a valid Row is fine
assert_eq!(Row::parse("12543")?.to_string(), "12543");
// Parsing valid rows with invalid characters is also fine
assert_eq!(Row::parse("4321\t[65 78]")?.to_string(), "43216578");
assert_eq!(Row::parse("3|2|1  6|5|4  9|8|7")?.to_string(), "321654987");
// Parsing an invalid `Row` returns an error describing the problem
assert_eq!(
    Row::parse("112345"),
    Err(InvalidRowError::DuplicateBell(Bell::from_number(1).unwrap()))
);
assert_eq!(
    Row::parse("12745"),
    Err(InvalidRowError::BellOutOfStage(
        Bell::from_name('7').unwrap(),
        Stage::DOUBLES
    ))
);

Creates rounds on a given Stage.

Example

use proj_core::{Row, Stage};

assert_eq!(Row::rounds(Stage::MINIMUS).to_string(), "1234");
assert_eq!(Row::rounds(Stage::CATERS).to_string(), "123456789");

Creates backrounds on a given Stage.

Example

use proj_core::{Row, Stage};

assert_eq!(Row::backrounds(Stage::MINIMUS).to_string(), "4321");
assert_eq!(Row::backrounds(Stage::CATERS).to_string(), "987654321");

Creates Queens on a given Stage.

Example

use proj_core::{Row, Stage};

assert_eq!(Row::queens(Stage::MINIMUS).to_string(), "1324");
assert_eq!(Row::queens(Stage::CATERS).to_string(), "135792468");

Creates a Row containing no Bells, but without causing any allocations. This is useful for initialising temporary Rows.

Utility function that creates a Row from an iterator of Bells, performing the validity check.

Example

use proj_core::{Bell, Row, Stage, InvalidRowError};

// Create a valid row from an iterator over `Bell`s
let iter = [0, 3, 4, 2, 1].iter().copied().map(Bell::from_index);
let row = Row::from_iter(iter)?;
assert_eq!(row.to_string(), "14532");
// Attempt to create an invalid row from an iterator over `Bell`s
// (we get an error)
let iter = [0, 3, 7, 2, 1].iter().copied().map(Bell::from_index);
assert_eq!(
    Row::from_iter(iter),
    Err(InvalidRowError::BellOutOfStage(
        Bell::from_name('8').unwrap(),
        Stage::DOUBLES,
    ))
);

All the Rows formed by repeatedly permuting a given Row. The first item returned will always be the input Row, and the last will always be rounds.

Example

use proj_core::{Row};

// The closure of "18234567" are all the fixed-treble cyclic part heads.
assert_eq!(
    Row::parse("18234567")?.closure(),
    vec![
        Row::parse("18234567")?,
        Row::parse("17823456")?,
        Row::parse("16782345")?,
        Row::parse("15678234")?,
        Row::parse("14567823")?,
        Row::parse("13456782")?,
        Row::parse("12345678")?,
    ]
);

Returns the Parity of this Row.

All the Rows formed by repeatedly permuting a given Row, but the first Row returned will always be rounds, rather than self. This is useful for situations like generating part heads, where it’s more intutive for the closure to start at rounds.

Example

use proj_core::{Row};

// The closure of "18234567" are all the fixed-treble cyclic part heads.
// Note how rounds is the first Row/part head generated
assert_eq!(
    Row::parse("18234567")?.closure_from_rounds(),
    vec![
        Row::parse("12345678")?,
        Row::parse("18234567")?,
        Row::parse("17823456")?,
        Row::parse("16782345")?,
        Row::parse("15678234")?,
        Row::parse("14567823")?,
        Row::parse("13456782")?,
    ]
);

Takes a sequence of sets of Rows ([X_1, X_2, ..., X_n]) and computes every product x_1 * x_2 * ... * x_n where x_i comes from X_i for all i.

Generates the least group containing a given set of Rows, returning the result in a HashSet (therefore, the result is unordered). The current algorithm is quite slow; if anyone knows of a better one, then please let me know…

Determines if the given set of Rows forms a group. This performs n^2 transpositions and n inversions where n is the number of unique elements yeilded by rows. See this Wikipedia page for the algorithm used.

Checks the validity of a potential Row, returning it if valid and returning an InvalidRowError otherwise (consuming the potential Row so it can’t be used).

Checks the validity of a potential Row, extending it to the given Stage if valid and returning an InvalidRowError otherwise (consuming the potential Row so it can’t be used). This will provide nicer errors than Row::check_validity since this has extra information about the desired Stage of the potential Row.

Gets the 0-indexed place at which a given Bell appears in this Row, returning None if the Bell is out of the stage. This performs a linear search of the Row.

Example

use proj_core::{Bell, Row};

let tittums = Row::parse("15263748").unwrap();
// The treble is leading in position 0
assert_eq!(tittums.place_of(Bell::from_name('1')?)?, 0);
// The '5' is at index `1`, because indices always start from zero
assert_eq!(tittums.place_of(Bell::from_name('5')?)?, 1);

Perform an in-place check that this Row is equal to rounds. x.is_rounds() is an optimised version of x == Row::rounds(x.stage()).

Example

use proj_core::{Row, Stage};

// Rounds is ... rounds (DOH)
assert!(Row::rounds(Stage::MAXIMUS).is_rounds());
// This is not rounds
assert!(!Row::parse("18423756")?.is_rounds());

Multiply two Rows (i.e. use the RHS to permute the LHS), checking that the Stages are compatible. This is like using [*](::mul), except that this returns a Result instead of panic!ing.

Example

use proj_core::{Row};

// Multiplying two Rows of the same Stage is fine
assert_eq!(
    Row::parse("13425678")?.mul(&Row::parse("43217568")?),
    Ok(Row::parse("24317568")?)
);
// Multiplying two Rows of different Stages causes an error but no
// undefined behaviour
assert_eq!(
    &Row::parse("13425678")?
        .mul(&Row::parse("4321")?)
        .unwrap_err()
        .to_string(),
    "Incompatible stages: Major (lhs), Minimus (rhs)"
);

Computes the value of r which satisfies r * self = other - i.e. the Row which pre-transposes self to other.

Computes the value of r which satisfies r * self = other - i.e. the Row which pre-transposes self to other, bypassing the same-Stage check.

Safety

This is safe if self and other have the same Stage.

Returns an iterator over the Bells in this Row

Returns an immutable reference to the underlying slice of Bells that makes up this Row.

Example

use proj_core::{Bell, Row};

let tittums = Row::parse("15263748")?;
assert_eq!(tittums.slice()[3], Bell::from_name('6').unwrap());

Concatenates the names of the Bells in this Row to the end of a String. Using row.to_string() will behave the same as this but will return an newly allocated String.

Example

use proj_core::{Row};

let waterfall = Row::parse("6543217890")?;
let mut string = "Waterfall is: ".to_owned();
waterfall.push_to_string(&mut string);
assert_eq!(string, "Waterfall is: 6543217890");

A very collision-resistant hash function. It is guarunteed to be perfectly collision-resistant on the following Stages:

  • 16-bit machines: Up to 6 bells
  • 32-bit machines: Up to 9 bells
  • 64-bit machines: Up to 16 bells

This hashing algorithm works by reading the row as a number using the stage as a base, thus guarunteeing that (ignoring overflow), two Rows will only be hashed to the same value if they are in fact the same. This is ludicrously inefficient in terms of hash density, but it is fast and perfect and in most cases will suffice.

Trait Implementations

Returns a copy of the value. Read more

Performs copy-assignment from source. Read more

Formats the value using the given formatter. Read more

Returns a String representing this Row.

Example

use proj_core::{Row, Stage};

assert_eq!(Row::rounds(Stage::MAJOR).to_string(), "12345678");
assert_eq!(Row::parse("146235")?.to_string(), "146235");

Feeds this value into the given Hasher. Read more

Feeds a slice of this type into the given Hasher. Read more

The returned type after indexing.

Performs the indexing (container[index]) operation. Read more

Uses the RHS to permute the LHS without consuming either argument.

Example

use proj_core::{Row};

// Multiplying two Rows of the same Stage just returns a new Row
assert_eq!(
    &Row::parse("13425678")? * &Row::parse("43217568")?,
    Row::parse("24317568")?
);
use proj_core::{Row};

// Multiplying two Rows of different Stages panics rather than
// producing undefined behaviour
let _unrow = &Row::parse("13425678")? * &Row::parse("4321")?;

The resulting type after applying the * operator.

See [&Row * &Row](<&Row as std::ops::Mul>::mul) for docs.

The resulting type after applying the * operator.

See [!&Row](<&Row as std::ops::Not>::not) for docs.

The resulting type after applying the ! operator.

Find the inverse of a Row. If X is the input Row, and Y = !X, then XY = YX = I where I is the identity on the same stage as X (i.e. rounds). This operation cannot fail, since valid Rows are guaruteed to have an inverse.

Example

use proj_core::{Row, Stage};

// The inverse of Queens is Tittums
assert_eq!(!Row::parse("135246")?, Row::parse("142536")?);
// Backrounds is self-inverse
assert_eq!(!Row::backrounds(Stage::MAJOR), Row::backrounds(Stage::MAJOR));
// `1324` inverts to `1423`
assert_eq!(!Row::parse("1342")?, Row::parse("1423")?);

The resulting type after applying the ! operator.

This method returns an Ordering between self and other. Read more

Compares and returns the maximum of two values. Read more

Compares and returns the minimum of two values. Read more

Restrict a value to a certain interval. Read more

This method tests for self and other values to be equal, and is used by ==. Read more

This method tests for !=.

This method returns an ordering between self and other values if one exists. Read more

This method tests less than (for self and other) and is used by the < operator. Read more

This method tests less than or equal to (for self and other) and is used by the <= operator. Read more

This method tests greater than (for self and other) and is used by the > operator. Read more

This method tests greater than or equal to (for self and other) and is used by the >= operator. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Performs the conversion.

Performs the conversion.

The resulting type after obtaining ownership.

Creates owned data from borrowed data, usually by cloning. Read more

🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

Uses borrowed data to replace owned data, usually by cloning. Read more

Converts the given value to a String. Read more

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.