1use std::mem;
2
3use derive_where::derive_where;
4
5use rand::{Rng, seq::IndexedRandom};
6use spru::common::error::AnyResult;
7use tagset::tagset;
8use telety::telety;
9
10use crate::cloned;
11
12#[derive(Debug)]
13pub struct Die<D: self::DieKind> {
14 die: D,
15 current_face: D::Face,
16}
17
18impl<D: self::DieKind> Die<D> {
19 pub fn current_face(&self) -> &D::Face {
20 &self.current_face
21 }
22}
23
24pub fn create<D: self::DieKind>(die: D) -> Create<D> {
25 let mut mock_rng = rand::rngs::mock::StepRng::new(0, 0);
26 let current_face = die.roll(&mut mock_rng);
27 cloned::create(Die { die, current_face })
28}
29
30pub fn roll<D: self::DieKind, R: rand::Rng>(state: &Die<D>, rng: &mut R) -> SetFace<D> {
33 let face = state.die.roll(rng);
34 set_face(face)
35}
36
37pub fn set_face<D: self::DieKind>(face: D::Face) -> SetFace<D> {
38 SetFace { face }
39}
40
41pub fn destroy<D: self::DieKind>() -> Destroy<D> {
42 cloned::destroy()
43}
44
45#[telety(crate::die)]
46#[tagset(Create<D>)]
47#[tagset(SetFace<D>)]
48#[tagset(Destroy<D>)]
49pub struct Actions<D: self::DieKind>;
50
51pub type Create<D> = cloned::Create<Die<D>>;
52
53#[derive_where(Debug, Clone; D::Face)]
54#[derive(serde::Serialize, serde::Deserialize, spru::action::Update)]
55pub struct SetFace<D: self::DieKind> {
56 face: D::Face,
57}
58
59impl<D: self::DieKind<Face: Clone>> spru::action::Update for SetFace<D> {
60 type T = Die<D>;
61 type Undo = Self;
62
63 fn update(&self, value: &mut Self::T) -> AnyResult<impl Into<Option<Self::Undo>>> {
64 let face = mem::replace(&mut value.current_face, self.face.clone());
65
66 Ok(Self { face })
67 }
68}
69
70pub type Destroy<D> = cloned::Destroy<Die<D>>;
71
72pub trait DieKind {
73 type Face;
74
75 fn roll<R: Rng>(&self, rng: &mut R) -> Self::Face;
76}
77
78#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
81pub struct DN<T>(T);
82
83impl<T> DN<T> {
84 pub fn new(n: T) -> Self {
85 Self(n)
86 }
87
88 pub fn n(&self) -> &T {
89 &self.0
90 }
91}
92
93impl<T> DieKind for DN<T>
94where
95 T: num_traits::Zero + rand::distr::uniform::SampleUniform + std::cmp::PartialOrd + Clone,
96{
97 type Face = T;
98
99 fn roll<R: Rng>(&self, rng: &mut R) -> Self::Face {
100 rng.random_range(T::zero()..self.0.clone())
101 }
102}
103
104#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
106pub struct Custom<T>(Vec<T>);
107
108impl<T> Custom<T> {
109 pub fn new(faces: Vec<T>) -> Self {
110 assert!(!faces.is_empty());
111 Self(faces)
112 }
113}
114
115impl<T: Clone> DieKind for Custom<T> {
116 type Face = T;
117
118 fn roll<R: Rng>(&self, rng: &mut R) -> Self::Face {
119 self.0.choose(rng).unwrap().clone()
120 }
121}