Skip to main content

RollSpec

Struct RollSpec 

Source
pub struct RollSpec {
    pub count: u32,
    pub sides: u32,
    pub keep: Option<Keep>,
}
Expand description

A specification for rolling one or more dice.

This struct defines how many dice to roll, how many sides each die has, and optionally which dice to keep (for advantage/disadvantage mechanics).

§Fields

  • count: The number of dice to roll
  • sides: The number of sides on each die
  • keep: Optional keep modifier (keep highest N or lowest N)

§Examples

§Basic dice roll

use dice_parser::RollSpec;

// Roll 2 six-sided dice
let spec = RollSpec::new(2, 6, None);

§Keep highest (advantage)

use dice_parser::{RollSpec, Keep};

// Roll 4d6, keep highest 3 (common for D&D ability scores)
let spec = RollSpec::new(4, 6, Some(Keep::Highest(3)));

§Keep lowest (disadvantage)

use dice_parser::{RollSpec, Keep};

// Roll 2d20, keep lowest 1 (disadvantage in D&D)
let spec = RollSpec::new(2, 20, Some(Keep::Lowest(1)));

Fields§

§count: u32

The number of dice to roll.

§sides: u32

The number of sides on each die.

§keep: Option<Keep>

Optional modifier to keep only highest or lowest N dice.

Implementations§

Source§

impl RollSpec

Source

pub fn new(count: u32, sides: u32, keep: Option<Keep>) -> Self

Create a new roll specification.

§Parameters
  • count: The number of dice to roll
  • sides: The number of sides on each die
  • keep: Optional keep modifier
§Examples
use dice_parser::{RollSpec, Keep};

// Simple 2d6 roll
let spec = RollSpec::new(2, 6, None);

// 4d6 keep highest 3
let spec = RollSpec::new(4, 6, Some(Keep::Highest(3)));
Examples found in repository?
examples/error_handling.rs (line 35)
5fn main() {
6    println!("=== Error Handling Examples ===\n");
7
8    // Parse error - invalid syntax
9    println!("1. Parse error (missing sides):");
10    match DiceExpr::parse("2d") {
11        Ok(_) => println!("  Unexpectedly succeeded!"),
12        Err(e) => println!("  Error: {}", e),
13    }
14    println!();
15
16    // Syntax error - negative dice count
17    println!("2. Syntax error (negative dice count):");
18    match DiceExpr::parse("-2d6") {
19        Ok(_) => println!("  Unexpectedly succeeded!"),
20        Err(e) => println!("  Error: {}", e),
21    }
22    println!();
23
24    // Trailing input error
25    println!("3. Trailing input error:");
26    match DiceExpr::parse("2d6 extra") {
27        Ok(_) => println!("  Unexpectedly succeeded!"),
28        Err(e) => println!("  Error: {}", e),
29    }
30    println!();
31
32    // Invalid spec error (keep more than rolled)
33    println!("4. Invalid roll specification:");
34    use dice_parser::{RollSpec, Keep};
35    let spec = RollSpec::new(2, 6, Some(Keep::Highest(5))); // Try to keep 5 dice when only rolling 2
36    let expr = DiceExpr::Roll(spec);
37    match expr.roll() {
38        Ok(_) => println!("  Unexpectedly succeeded!"),
39        Err(e) => println!("  Error: {}", e),
40    }
41    println!();
42
43    // Pattern matching on error types
44    println!("5. Pattern matching on DiceError:");
45    let result = DiceExpr::parse("abc");
46    match result {
47        Ok(_) => println!("  Unexpectedly succeeded!"),
48        Err(DiceError::ParseError { kind, input, start, stop: _ }) => {
49            println!("  Parse error at position {}: {:?}", start, kind);
50            println!("  Input: {}", input);
51        }
52        Err(e) => println!("  Other error: {}", e),
53    }
54}
More examples
Hide additional examples
examples/basic_usage.rs (line 16)
5fn main() {
6    println!("=== Basic Parsing and Rolling ===");
7    let expr = DiceExpr::parse("2d6+3").unwrap();
8    let result = expr.roll().unwrap();
9    println!("Expression: 2d6+3");
10    println!("Total: {}", result.total);
11    println!("Rolls: {:?}", result.rolls);
12    println!("Modifier: {}", result.modifier);
13    println!();
14
15    println!("=== Manual Construction ===");
16    let roll_spec = RollSpec::new(4, 6, Some(Keep::Highest(3)));
17    let expr = DiceExpr::Roll(roll_spec);
18    let result = expr.roll().unwrap();
19    println!("Expression: 4d6 keep highest 3");
20    println!("Total: {}", result.total);
21    println!("All rolls: {:?}", result.rolls);
22    println!();
23
24    println!("=== Complex Expression ===");
25    let d2d6 = DiceExpr::Roll(RollSpec::new(2, 6, None));
26    let d1d4 = DiceExpr::Roll(RollSpec::new(1, 4, None));
27    let modifier = DiceExpr::Literal(2);
28    let sum = DiceExpr::Sum(Box::new(d2d6), Box::new(d1d4));
29    let expr = DiceExpr::Difference(Box::new(sum), Box::new(modifier));
30    let result = expr.roll().unwrap();
31    println!("Expression: (2d6 + 1d4) - 2");
32    println!("Total: {}", result.total);
33    println!();
34
35    println!("=== D&D 5e Advantage ===");
36    let advantage = DiceExpr::Roll(RollSpec::new(2, 20, Some(Keep::Highest(1))));
37    let result = advantage.roll().unwrap();
38    println!("Expression: 2d20 keep highest 1 (advantage)");
39    println!("Rolls: {:?}", result.rolls);
40    println!("Result: {}", result.total);
41    println!();
42
43    println!("=== D&D 5e Disadvantage ===");
44    let disadvantage = DiceExpr::Roll(RollSpec::new(2, 20, Some(Keep::Lowest(1))));
45    let result = disadvantage.roll().unwrap();
46    println!("Expression: 2d20 keep lowest 1 (disadvantage)");
47    println!("Rolls: {:?}", result.rolls);
48    println!("Result: {}", result.total);
49    println!();
50
51    println!("=== Character Ability Scores ===");
52    println!("Rolling 4d6 drop lowest for 6 abilities:");
53    let ability_roll = DiceExpr::Roll(RollSpec::new(4, 6, Some(Keep::Highest(3))));
54    for i in 0..6 {
55        let result = ability_roll.roll().unwrap();
56        println!("  Ability {}: {} (rolls: {:?})", i + 1, result.total, result.rolls);
57    }
58}
examples/complete_api.rs (line 24)
8fn main() {
9    // ========================================
10    // 1. DiceExpr - The main expression type
11    // ========================================
12
13    // 1.1 Parsing from string
14    println!("1. Parsing and expressions");
15    let parsed = DiceExpr::parse("2d6+3").unwrap();
16    println!("  1.1 Parsing e.g. \"2d6+3\" yields:");
17    println!("    {:?}", parsed);
18
19    // 1.2 DiceExpr variants - all publicly accessible
20    let literal = DiceExpr::Literal(5);
21    println!("  1.2 A literal expression \"5\": ");
22    println!("    {:?}", literal);
23
24    let roll = DiceExpr::Roll(RollSpec::new(2, 6, None));
25    println!("  1.3 A single roll expression corresponding to 2d6:",);
26    println!("    {:?}", roll);
27
28    let sum = DiceExpr::Sum(Box::new(roll.clone()), Box::new(literal.clone()));
29    println!("  1.4 A sum of two expression, e.g. \"2d6+5\":");
30    println!("    {:?}", sum);
31
32    let _diff = DiceExpr::Difference(Box::new(roll.clone()), Box::new(DiceExpr::Literal(1)));
33    println!("  1.5 A difference of two expressions, e.g. \"2d6-1\":",);
34    println!("    {:?}", _diff);
35
36    // 1.3 Rolling methods
37    println!("\n  1.6 DiceExpr::roll() - Rolling expressions");
38    let result1 = parsed.roll().unwrap();
39    println!("    An expression, 2d6+3: {}", result1.total);
40    let result2 = literal.roll().unwrap();
41    println!("    A literal 5: {}", result2.total);
42    let result3 = roll.roll().unwrap();
43    println!("    A single roll 2d6: {}", result3.total);
44    let result4 = sum.roll().unwrap();
45    println!("    A manual sum, 2d6+5: {}", result4.total);
46    let result5 = _diff.roll().unwrap();
47    println!("    A manual diff, 2d6-1: {}", result5.total);
48
49    println!("\n   1.7 DiceExpr::roll_with_rng() - Roll with custom RNG");
50    let rng = StdRng::seed_from_u64(42);
51    let result6 = DiceExpr::parse("1d20").unwrap().roll_with_rng(rng).unwrap();
52    println!("       Rolling 1d20: {}", result6.total);
53
54    // ========================================
55    // 2. RollSpec - Dice roll specification
56    // ========================================
57    println!("\n2. RollSpec Usage:");
58    println!("   Struct with public fields and constructor\n");
59
60    let spec = RollSpec::new(4, 6, Some(Keep::Highest(3)));
61    println!("   RollSpec::new(4, 6, Some(Keep::Highest(3)))");
62    println!("   - count: {}", spec.count);
63    println!("   - sides: {}", spec.sides);
64    println!("   - keep: {:?}", spec.keep);
65
66    // ========================================
67    // 3. Keep - Keep modifier enum
68    // ========================================
69    println!("\n3. Keep Usage:");
70    println!("   Enum with public variants\n");
71
72    let _keep_high = Keep::Highest(3);
73    println!("   {:?} - Keep 3 highest dice", _keep_high);
74
75    let _keep_low = Keep::Lowest(1);
76    println!("   {:?} - Keep 1 lowest die", _keep_high);
77
78    // Use in RollSpec
79    let _advantage = RollSpec::new(2, 20, Some(Keep::Highest(1)));
80    let _disadvantage = RollSpec::new(2, 20, Some(Keep::Lowest(1)));
81    println!("\n  Example with Advantage:");
82    println!(
83        "    {:?}, result: {}",
84        _advantage,
85        DiceExpr::Roll(_advantage.clone()).roll().unwrap().total
86    );
87    println!("\n  Example with Disadvantage:");
88    println!(
89        "    {:?}, result: {}",
90        _disadvantage,
91        DiceExpr::Roll(_disadvantage.clone()).roll().unwrap().total
92    );
93
94    // ========================================
95    // 4. ExprResult - Roll result
96    // ========================================
97    println!("\n4. ExprResult Usage:");
98    println!("   Struct with public fields\n");
99
100    let expr = DiceExpr::parse("2d6+3").unwrap();
101    let result: ExprResult = expr.roll().unwrap();
102
103    println!("   ExprResult from rolling 2d6+3:");
104    println!("   - total: {} (final result)", result.total);
105    println!("   - rolls: {:?} (individual dice)", result.rolls);
106    println!("   - modifier: {} (constant modifiers)", result.modifier);
107
108    // ========================================
109    // 5. DiceError - Error handling
110    // ========================================
111    println!("\n5. DiceError Usage:");
112    println!("   Enum with public variants for error handling\n");
113
114    // ParseError variant
115    if let Err(DiceError::ParseError {
116        kind,
117        input,
118        start,
119        stop: _,
120    }) = DiceExpr::parse("invalid")
121    {
122        println!("   DiceError::ParseError:");
123        println!("   - kind: {:?}", kind);
124        println!("   - input: {}", input);
125        println!("   - start: {}", start);
126    }
127
128    // SyntaxError variant
129    if let Err(DiceError::SyntaxError { expected, .. }) = DiceExpr::parse("-2d6") {
130        println!("\n   DiceError::SyntaxError:");
131        if let Some(exp) = expected {
132            println!("   - expected: {}", exp);
133        }
134    }
135
136    // TrailingInput variant
137    if let Err(DiceError::TrailingInput { pos, .. }) = DiceExpr::parse("2d6 extra") {
138        println!("\n   DiceError::TrailingInput:");
139        println!("   - pos: {}", pos);
140    }
141
142    // InvalidSpec variant
143    let bad_spec = RollSpec::new(2, 6, Some(Keep::Highest(5)));
144    if let Err(DiceError::InvalidSpec(spec, msg)) = DiceExpr::Roll(bad_spec).roll() {
145        println!("\n   DiceError::InvalidSpec:");
146        println!("   - spec: {:?}", spec);
147        println!("   - message: {}", msg);
148    }
149
150    // ========================================
151    // 6. Complete Example
152    // ========================================
153    println!("\n6. Complete Example:");
154    println!("   Building a complex expression with all features\n");
155
156    // Character creation: 6 abilities, each 4d6 keep highest 3
157    println!("   Rolling D&D ability scores (4d6 drop lowest):");
158    let ability_roll = DiceExpr::Roll(RollSpec::new(4, 6, Some(Keep::Highest(3))));
159
160    for i in 1..=6 {
161        if let Ok(result) = ability_roll.roll() {
162            println!(
163                "   Ability {}: {} (rolls: {:?})",
164                i, result.total, result.rolls
165            );
166        }
167    }
168}

Trait Implementations§

Source§

impl Clone for RollSpec

Source§

fn clone(&self) -> RollSpec

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for RollSpec

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

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

fn clone_into(&self, target: &mut T)

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

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V