1use std::collections::BTreeMap;
26use std::sync::Arc;
27
28use crate::core::{Fields, Value};
29use crate::pmap::PMap;
30use crate::ty::{Ty, TyDecl};
31
32#[derive(Clone, Debug, PartialEq, Eq)]
34pub struct Uninhabitable {
35 pub ty: String,
36 pub why: &'static str,
37}
38
39impl std::fmt::Display for Uninhabitable {
40 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41 write!(f, "cannot invent a `{}`: {}", self.ty, self.why)
42 }
43}
44
45impl std::error::Error for Uninhabitable {}
46
47type Types = BTreeMap<Arc<str>, TyDecl>;
48
49#[derive(Clone, Debug)]
52pub struct Rng {
53 state: u64,
54}
55
56impl Rng {
57 pub fn seeded(name: &str, run: u64) -> Rng {
59 let mut h: u64 = 0xcbf2_9ce4_8422_2325;
60 for b in name.as_bytes() {
61 h ^= *b as u64;
62 h = h.wrapping_mul(0x0000_0100_0000_01b3);
63 }
64 Rng {
65 state: h ^ run.wrapping_mul(0x9e37_79b9_7f4a_7c15),
66 }
67 }
68
69 pub fn next_u64(&mut self) -> u64 {
70 self.state = self.state.wrapping_add(0x9e37_79b9_7f4a_7c15);
71 let mut z = self.state;
72 z = (z ^ (z >> 30)).wrapping_mul(0xbf58_476d_1ce4_e5b9);
73 z = (z ^ (z >> 27)).wrapping_mul(0x94d0_49bb_1331_11eb);
74 z ^ (z >> 31)
75 }
76
77 fn below(&mut self, n: usize) -> usize {
78 if n == 0 {
79 0
80 } else {
81 (self.next_u64() % n as u64) as usize
82 }
83 }
84}
85
86pub fn canonical(ty: &Ty, types: &Types) -> Result<Value, Uninhabitable> {
93 build(ty, types, None, 0)
94}
95
96pub fn arbitrary(ty: &Ty, types: &Types, rng: &mut Rng) -> Result<Value, Uninhabitable> {
98 build(ty, types, Some(rng), 0)
99}
100
101const MAX_DEPTH: usize = 4;
104
105fn build(
106 ty: &Ty,
107 types: &Types,
108 mut rng: Option<&mut Rng>,
109 depth: usize,
110) -> Result<Value, Uninhabitable> {
111 let (name, args) = match ty {
112 Ty::Con(n, args) => (n.as_ref(), args.as_slice()),
113 Ty::Var(_) => {
116 return Err(Uninhabitable {
117 ty: ty.to_string(),
118 why: "it is still a type variable — write the type down",
119 })
120 }
121 Ty::Fun(..) => {
122 return Err(Uninhabitable {
123 ty: ty.to_string(),
124 why: "a function is code, and the generator invents data",
125 })
126 }
127 };
128 if depth >= MAX_DEPTH {
130 rng = None;
131 }
132 let mut rng = rng;
133
134 match name {
135 Ty::UNIT => return Ok(Value::Unit),
136 Ty::BOOL => {
137 return Ok(Value::Bool(match reborrow(&mut rng) {
138 Some(r) => r.next_u64() & 1 == 1,
139 None => false,
140 }))
141 }
142 Ty::INT => {
143 return Ok(Value::Int(match reborrow(&mut rng) {
144 Some(r) => (r.next_u64() % 21) as i64 - 10,
147 None => 0,
148 }));
149 }
150 Ty::FLOAT => {
151 return Ok(Value::float(match reborrow(&mut rng) {
152 Some(r) => (r.next_u64() % 2001) as f64 / 100.0 - 10.0,
153 None => 0.0,
154 }))
155 }
156 Ty::STR => {
157 return Ok(Value::str_(match reborrow(&mut rng) {
158 Some(r) => WORDS[r.below(WORDS.len())],
159 None => "",
160 }))
161 }
162 Ty::HTML | Ty::ATTR => {
165 return Err(Uninhabitable {
166 ty: ty.to_string(),
167 why: "a view is rendered from a state, not invented",
168 })
169 }
170 Ty::SECRET => {
173 return Err(Uninhabitable {
174 ty: ty.to_string(),
175 why: "a secret has to be written out by a person, never invented by a generator",
176 })
177 }
178 Ty::LIST => {
179 let elem = args.first().cloned().unwrap_or_else(Ty::unit);
180 let n = match reborrow(&mut rng) {
181 Some(r) => r.below(4),
182 None => 0,
183 };
184 let mut out = Vec::with_capacity(n);
185 for i in 0..n {
186 out.push(build(&elem, types, reborrow(&mut rng), depth + 1 + i)?);
187 }
188 return Ok(Value::List(Arc::new(out)));
189 }
190 Ty::MAP => {
191 let k = args.first().cloned().unwrap_or_else(Ty::unit);
192 let v = args.get(1).cloned().unwrap_or_else(Ty::unit);
193 let n = match reborrow(&mut rng) {
194 Some(r) => r.below(3),
195 None => 0,
196 };
197 let mut m = PMap::new();
198 for i in 0..n {
199 let key = build(&k, types, reborrow(&mut rng), depth + 1 + i)?;
200 let val = build(&v, types, reborrow(&mut rng), depth + 1 + i)?;
201 m = m.insert(key, val);
202 }
203 return Ok(Value::Map(m));
204 }
205 Ty::STREAM | Ty::SIGNAL => {
207 return Err(Uninhabitable {
208 ty: ty.to_string(),
209 why: "a signal is a node in the program's graph, not a value",
210 })
211 }
212 _ => {}
213 }
214
215 match types.get(name) {
216 Some(TyDecl::Newtype { inner, .. }) => {
217 let v = build(inner, types, rng, depth + 1)?;
218 Ok(Value::data(
219 Arc::from(name),
220 None,
221 Fields::from_iter([(Arc::from("value"), v)]),
222 ))
223 }
224 Some(TyDecl::Alias { ty: inner, .. }) => build(inner, types, rng, depth),
225 Some(TyDecl::Model { fields, .. }) => {
226 let fields = fields.clone();
227 let mut out = Fields::new();
228 for (i, (fname, fty)) in fields.iter().enumerate() {
229 let fty = crate::ty::instantiate_decl(fty, args);
230 out.insert(
231 fname.clone(),
232 build(&fty, types, reborrow(&mut rng), depth + 1 + i)?,
233 );
234 }
235 Ok(Value::data(Arc::from(name), None, out))
236 }
237 Some(TyDecl::Union { variants, .. }) => {
238 if variants.is_empty() {
239 return Err(Uninhabitable {
240 ty: ty.to_string(),
241 why: "it has no variants",
242 });
243 }
244 let variants = variants.clone();
245 let idx = match reborrow(&mut rng) {
248 Some(r) => r.below(variants.len()),
249 None => variants
250 .iter()
251 .position(|v| !v.fields.iter().any(|(_, t)| t.con_name() == Some(name)))
252 .unwrap_or(0),
253 };
254 let v = &variants[idx];
255 let mut out = Fields::new();
256 for (i, (fname, fty)) in v.fields.iter().enumerate() {
257 let fty = crate::ty::instantiate_decl(fty, args);
258 out.insert(
259 fname.clone(),
260 build(&fty, types, reborrow(&mut rng), depth + 1 + i)?,
261 );
262 }
263 Ok(Value::data(Arc::from(name), Some(v.name.clone()), out))
264 }
265 _ => Err(Uninhabitable {
266 ty: ty.to_string(),
267 why: "this program does not declare it",
268 }),
269 }
270}
271
272fn reborrow<'a, 'b: 'a>(r: &'a mut Option<&'b mut Rng>) -> Option<&'a mut Rng> {
273 r.as_deref_mut()
274}
275
276pub fn shrink(v: &Value) -> Vec<Value> {
283 let mut out = Vec::new();
284 match v {
285 Value::Int(0) | Value::Bool(false) | Value::Unit => {}
286 Value::Int(n) => {
287 out.push(Value::Int(0));
288 if n.abs() > 1 {
289 out.push(Value::Int(n / 2));
290 }
291 if *n > 0 {
292 out.push(Value::Int(n - 1));
293 } else {
294 out.push(Value::Int(n + 1));
295 }
296 }
297 Value::Bool(true) => out.push(Value::Bool(false)),
298 Value::Float(_) => {
299 if v.as_f64() != Some(0.0) {
300 out.push(Value::float(0.0));
301 }
302 }
303 Value::Str(s) if !s.is_empty() => {
304 out.push(Value::str_(""));
305 if s.len() > 1 {
306 out.push(Value::str_(&s[..s.len() / 2]));
307 }
308 }
309 Value::List(xs) if !xs.is_empty() => {
310 out.push(Value::List(Arc::new(Vec::new())));
311 if xs.len() > 1 {
312 out.push(Value::List(Arc::new(xs[..xs.len() / 2].to_vec())));
313 out.push(Value::List(Arc::new(xs[1..].to_vec())));
314 }
315 for (i, x) in xs.iter().enumerate() {
318 for smaller in shrink(x) {
319 let mut copy = xs.as_ref().clone();
320 copy[i] = smaller;
321 out.push(Value::List(Arc::new(copy)));
322 }
323 }
324 }
325 Value::Map(m) if !m.is_empty() => {
326 out.push(Value::Map(PMap::new()));
327 if let Some((k, _)) = m.iter().next() {
328 out.push(Value::Map(m.remove(k)));
329 }
330 }
331 Value::Data(d) => {
332 for (name, f) in d.fields.iter() {
333 for smaller in shrink(f) {
334 let mut copy = d.fields.clone();
335 copy.insert(name.clone(), smaller);
336 out.push(Value::data(d.ty.clone(), d.variant.clone(), copy));
337 }
338 }
339 }
340 _ => {}
341 }
342 let before = size(v);
343 out.retain(|c| size(c) < before);
344 out
345}
346
347pub fn size(v: &Value) -> u64 {
349 match v {
350 Value::Unit => 0,
351 Value::Bool(b) => *b as u64,
352 Value::Int(n) => n.unsigned_abs(),
353 Value::Float(_) => v.as_f64().map(|f| f.abs() as u64).unwrap_or(0),
354 Value::Str(s) => s.len() as u64,
355 Value::List(xs) => 1 + xs.iter().map(size).sum::<u64>(),
356 Value::Map(m) => 1 + m.iter().map(|(k, val)| size(k) + size(val)).sum::<u64>(),
357 Value::Data(d) => d.fields.values().map(size).sum::<u64>(),
358 Value::Html(_) | Value::Attr(_) | Value::Closure(_) => 1,
359 }
360}
361
362const WORDS: &[&str] = &["", "a", "milk", "bread", " ", "ana", "bo", "x"];
365
366#[cfg(test)]
367mod tests {
368 use super::*;
369 use crate::ty::Variant;
370
371 fn types() -> Types {
372 let mut t = crate::prelude::types();
373 t.insert(
374 Arc::from("Id"),
375 TyDecl::Newtype {
376 name: Arc::from("Id"),
377 params: Vec::new(),
378 inner: Ty::str_(),
379 },
380 );
381 t.insert(
382 Arc::from("Event"),
383 TyDecl::Union {
384 name: Arc::from("Event"),
385 params: Vec::new(),
386 variants: vec![
387 Variant {
388 name: Arc::from("Added"),
389 fields: vec![(Arc::from("id"), Ty::con("Id"))],
390 },
391 Variant {
392 name: Arc::from("Toggled"),
393 fields: vec![(Arc::from("id"), Ty::con("Id"))],
394 },
395 ],
396 },
397 );
398 t
399 }
400
401 #[test]
402 fn the_canonical_inhabitant_is_the_smallest_obvious_one() {
403 let t = types();
404 assert_eq!(canonical(&Ty::int(), &t).unwrap(), Value::Int(0));
405 assert_eq!(canonical(&Ty::str_(), &t).unwrap(), Value::str_(""));
406 assert_eq!(canonical(&Ty::bool_(), &t).unwrap(), Value::Bool(false));
407 assert_eq!(
408 canonical(&Ty::list(Ty::con("Event")), &t).unwrap(),
409 Value::List(Arc::new(Vec::new()))
410 );
411 let e = canonical(&Ty::con("Event"), &t).unwrap();
413 assert_eq!(e.variant(), Some("Added"));
414 assert_eq!(e.field("id").unwrap().display(), "");
415 }
416
417 #[test]
418 fn a_secret_is_refused_because_somebody_has_to_type_it_out() {
419 let t = types();
420 let err = canonical(&Ty::secret(Ty::str_()), &t).expect_err("a secret is not invented");
421 assert!(err.why.contains("written out by a person"), "{err}");
422 let mut t2 = t.clone();
424 t2.insert(
425 Arc::from("Creds"),
426 TyDecl::Model {
427 name: Arc::from("Creds"),
428 params: Vec::new(),
429 fields: vec![(Arc::from("key"), Ty::secret(Ty::str_()))],
430 },
431 );
432 assert!(canonical(&Ty::con("Creds"), &t2).is_err());
433 }
434
435 #[test]
436 fn generation_is_a_function_of_the_seed_and_nothing_else() {
437 let t = types();
438 let ty = Ty::list(Ty::con("Event"));
439 let a = arbitrary(&ty, &t, &mut Rng::seeded("a property", 7)).unwrap();
440 let b = arbitrary(&ty, &t, &mut Rng::seeded("a property", 7)).unwrap();
441 assert_eq!(a, b, "the same seed must produce the same value");
442 let c = arbitrary(&ty, &t, &mut Rng::seeded("a property", 8)).unwrap();
443 let d = arbitrary(&ty, &t, &mut Rng::seeded("a property", 8)).unwrap();
446 assert_eq!(c, d);
447 }
448
449 #[test]
450 fn a_recursive_union_terminates() {
451 let mut t = types();
452 t.insert(
453 Arc::from("Tree"),
454 TyDecl::Union {
455 name: Arc::from("Tree"),
456 params: Vec::new(),
457 variants: vec![
458 Variant {
459 name: Arc::from("Node"),
460 fields: vec![
461 (Arc::from("l"), Ty::con("Tree")),
462 (Arc::from("r"), Ty::con("Tree")),
463 ],
464 },
465 Variant {
466 name: Arc::from("Leaf"),
467 fields: vec![],
468 },
469 ],
470 },
471 );
472 assert_eq!(
474 canonical(&Ty::con("Tree"), &t).unwrap().variant(),
475 Some("Leaf")
476 );
477 for run in 0..20 {
479 arbitrary(&Ty::con("Tree"), &t, &mut Rng::seeded("t", run)).unwrap();
480 }
481 }
482
483 #[test]
484 fn every_shrink_is_strictly_smaller_so_the_loop_terminates() {
485 let t = types();
486 for run in 0..50 {
487 let v = arbitrary(&Ty::list(Ty::con("Event")), &t, &mut Rng::seeded("s", run)).unwrap();
488 for c in shrink(&v) {
489 assert!(size(&c) < size(&v), "{c:?} is not smaller than {v:?}");
490 }
491 }
492 assert!(shrink(&Value::Int(0)).is_empty());
493 assert!(shrink(&Value::List(Arc::new(Vec::new()))).is_empty());
494 }
495
496 #[test]
497 fn a_type_parameter_reaches_the_field_it_stands_for() {
498 let t = types();
499 let v = canonical(&Ty::app(Ty::OPTION, vec![Ty::int()]), &t).unwrap();
500 assert_eq!(v.variant(), Some("Some"));
502 assert_eq!(v.field("value"), Some(&Value::Int(0)));
503 }
504}