Skip to main content

rdice_core/
die.rs

1//! Dice value objects.
2//!
3//! This module contains the serializable representation of dice and die faces.
4//! Built-in dice use numeric faces; custom dice may mix numeric and text faces.
5
6use serde::{Deserialize, Serialize};
7
8/// A single face on a die.
9///
10/// Integer faces contribute their value to roll sums and point analysis. Text
11/// faces render as text and contribute zero points during analysis.
12#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
13#[serde(tag = "type", content = "value")]
14pub enum FaceValue {
15    /// A numeric face value.
16    #[serde(rename = "integer")]
17    Integer(i64),
18    /// A text face value.
19    #[serde(rename = "text")]
20    Text(String),
21}
22
23impl std::fmt::Display for FaceValue {
24    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25        match self {
26            FaceValue::Integer(n) => write!(f, "{n}"),
27            FaceValue::Text(s) => write!(f, "{s}"),
28        }
29    }
30}
31
32/// Classifies whether a die is provided by the crate or supplied by a caller.
33#[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)]
34pub enum DieKind {
35    /// One of the built-in numeric dice.
36    Builtin,
37    /// A caller-defined die.
38    #[default]
39    Custom,
40}
41
42/// A die with a stable name and ordered set of faces.
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct Die {
45    /// Canonical die name.
46    ///
47    /// Built-in dice are named `D4`, `D6`, `D8`, `D10`, `D12`, `D20`, and
48    /// `D100`. Custom dice are stored with [`CUSTOM_PREFIX`].
49    pub name: String,
50    /// Ordered set of faces that may be rolled.
51    pub faces: Vec<FaceValue>,
52    /// Whether this die is built-in or custom.
53    #[serde(default)]
54    pub kind: DieKind,
55}
56
57/// Prefix used for canonical custom die names.
58pub const CUSTOM_PREFIX: &str = "\u{273d}";
59
60/// Returns the built-in numeric dice.
61///
62/// The built-in set contains `D4`, `D6`, `D8`, `D10`, `D12`, `D20`, and
63/// `D100`.
64pub fn builtin_dice() -> Vec<Die> {
65    [4, 6, 8, 10, 12, 20, 100]
66        .into_iter()
67        .map(|n| Die {
68            name: format!("D{n}"),
69            faces: (1..=n).map(|i| FaceValue::Integer(i as i64)).collect(),
70            kind: DieKind::Builtin,
71        })
72        .collect()
73}