1use crate::{
2 generate::{Generate, State},
3 shrink::Shrink,
4};
5use core::{any::Any, fmt};
6
7pub struct Boxed<I> {
8 generator: Box<dyn Any>,
9 generate: fn(&dyn Any, &mut State) -> Shrinker<I>,
10 constant: fn(&dyn Any) -> bool,
11}
12
13pub struct Shrinker<I> {
14 shrinker: Box<dyn Any>,
15 clone: fn(&dyn Any) -> Box<dyn Any>,
16 item: fn(&dyn Any) -> I,
17 shrink: fn(&mut dyn Any) -> Option<Box<dyn Any>>,
18}
19
20impl<I> fmt::Debug for Boxed<I> {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 f.debug_tuple("Boxed").field(&self.generator).finish()
23 }
24}
25
26impl<I> fmt::Debug for Shrinker<I> {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 f.debug_tuple("Shrinker").field(&self.shrinker).finish()
29 }
30}
31
32impl<I> Generate for Boxed<I> {
33 type Item = I;
34 type Shrink = Shrinker<I>;
35
36 fn generate(&self, state: &mut State) -> Self::Shrink {
37 (self.generate)(self.generator.as_ref(), state)
38 }
39
40 fn constant(&self) -> bool {
41 (self.constant)(self.generator.as_ref())
42 }
43}
44
45impl<I> Boxed<I> {
46 #[rustversion::since(1.75)]
47 pub(crate) const fn new<G: Generate<Item = I> + 'static>(generator: Box<G>) -> Self
48 where
49 G::Shrink: 'static,
50 {
51 Self {
52 generator,
53 generate: generate::<G>,
54 constant: constant::<G>,
55 }
56 }
57
58 #[rustversion::before(1.75)]
59 pub(crate) fn new<G: Generate<Item = I> + 'static>(generator: Box<G>) -> Self
60 where
61 G::Shrink: 'static,
62 {
63 Self {
64 generator,
65 generate: generate::<G>,
66 constant: constant::<G>,
67 }
68 }
69
70 pub fn downcast<G: Generate + 'static>(self) -> Result<Box<G>, Self> {
71 match self.generator.downcast::<G>() {
72 Ok(generator) => Ok(generator),
73 Err(generator) => Err(Self {
74 generator,
75 generate: self.generate,
76 constant: self.constant,
77 }),
78 }
79 }
80}
81
82impl<I> Shrinker<I> {
83 pub(crate) fn new<S: Shrink<Item = I> + 'static>(shrinker: Box<S>) -> Self {
84 Self {
85 shrinker,
86 clone: clone::<S>,
87 item: item::<S>,
88 shrink: shrink::<S>,
89 }
90 }
91
92 pub fn downcast<S: Shrink + 'static>(self) -> Result<Box<S>, Self> {
93 match self.shrinker.downcast::<S>() {
94 Ok(shrinker) => Ok(shrinker),
95 Err(shrinker) => Err(Self {
96 shrinker,
97 clone: self.clone,
98 item: self.item,
99 shrink: self.shrink,
100 }),
101 }
102 }
103}
104
105impl<I> Clone for Shrinker<I> {
106 fn clone(&self) -> Self {
107 Self {
108 shrinker: (self.clone)(self.shrinker.as_ref()),
109 clone: self.clone,
110 item: self.item,
111 shrink: self.shrink,
112 }
113 }
114}
115
116impl<I> Shrink for Shrinker<I> {
117 type Item = I;
118
119 fn item(&self) -> Self::Item {
120 (self.item)(self.shrinker.as_ref())
121 }
122
123 fn shrink(&mut self) -> Option<Self> {
124 Some(Self {
125 shrinker: (self.shrink)(self.shrinker.as_mut())?,
126 clone: self.clone,
127 item: self.item,
128 shrink: self.shrink,
129 })
130 }
131}
132
133fn generate<G: Generate + 'static>(generator: &dyn Any, state: &mut State) -> Shrinker<G::Item>
134where
135 G::Shrink: 'static,
136{
137 Shrinker::new(Box::new(
138 generator.downcast_ref::<G>().unwrap().generate(state),
139 ))
140}
141
142fn constant<G: Generate + 'static>(generator: &dyn Any) -> bool {
143 generator.downcast_ref::<G>().unwrap().constant()
144}
145
146fn clone<S: Shrink + 'static>(shrinker: &dyn Any) -> Box<dyn Any> {
147 Box::new(shrinker.downcast_ref::<S>().unwrap().clone())
148}
149
150fn item<S: Shrink + 'static>(shrinker: &dyn Any) -> S::Item {
151 shrinker.downcast_ref::<S>().unwrap().item()
152}
153
154fn shrink<S: Shrink + 'static>(shrinker: &mut dyn Any) -> Option<Box<dyn Any>> {
155 Some(Box::new(shrinker.downcast_mut::<S>().unwrap().shrink()?))
156}