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}