Skip to main content

rdice_core/
tray.rs

1//! Persistent dice tray data structures.
2//!
3//! A tray groups dice into slots so callers can roll the group repeatedly while
4//! locking selected slots between rolls.
5
6use super::die::FaceValue;
7use serde::{Deserialize, Serialize};
8
9/// A single die slot inside a [`Tray`].
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct TraySlot {
12    /// Canonical name of the die assigned to this slot.
13    pub die_name: String,
14    /// Stable slot identifier within the tray.
15    pub slot_id: u32,
16    /// Whether rolling the tray should preserve this slot's current value.
17    pub locked: bool,
18    /// Most recent rolled value for this slot.
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub current_value: Option<FaceValue>,
21}
22
23/// A named collection of dice slots.
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct Tray {
26    /// Tray name.
27    pub name: String,
28    /// Slots currently assigned to the tray.
29    #[serde(default)]
30    pub slots: Vec<TraySlot>,
31    /// Next slot identifier to assign.
32    ///
33    /// Slot identifiers are auto-incrementing and are not reused after a slot is
34    /// removed from the tray.
35    #[serde(default = "default_next_slot_id")]
36    pub next_slot_id: u32,
37}
38
39fn default_next_slot_id() -> u32 {
40    1
41}
42
43impl Tray {
44    /// Creates an empty tray with slot identifiers starting at `1`.
45    pub fn new(name: String) -> Self {
46        Self {
47            name,
48            slots: Vec::new(),
49            next_slot_id: 1,
50        }
51    }
52}