scratch_test_value/conversions/to_bool.rs
1use crate::{QuirkSink, SValue};
2
3/// Generated by [`SValue::q_as_bool`]
4///
5/// As Scratch blocks don't allow placing an expression block inside
6/// of an comparison context
7/// (block shapes, round blocks can't be placed in wholes of shape <..>)
8/// this shouldn't occur for normal user programs.
9pub enum SValueToBoolQ {
10 /// Boolean conversion for empty string returned [false]
11 EmptyStringTreatedAsFalse,
12 /// Boolean conversion of a non-empty string returned [true]
13 NonEmptyStringTreatedAsTrue,
14 /// The integer or float number zero was converted to [false]
15 ZeroToFalse,
16 /// The integer or float number one was converted to [true]
17 OneToTrue,
18 /// An integer that was neither zero nor one was converted to [true]
19 IntToBoolNotLossless(i64),
20 /// A float that was neither zero nor one was converted to [true]
21 FloatToBoolNotLossless(f64),
22}
23
24impl SValue {
25 /// Converts the value to a boolean according to Scratch logic.
26 ///
27 /// | input | associated boolean |
28 /// | :---------------- | :------------------- |
29 /// | `""` | `false` |
30 /// | `"false"` | `false` |
31 /// | `"true"` | `true` |
32 /// | Int 0 / Float 0.0 | `false` |
33 /// | Int 1 / Float 1.0 | `true` |
34 /// | other string | `true` |
35 /// | other number | `true` |
36 /// | already boolean | _unchanged_ |
37 ///
38 /// Occuring behaviour differences Scratch implements to avoid errors
39 /// will be reported to the sink.
40 ///
41 /// As expression blocks can't be placed in comparison contexts
42 /// these quriks should never occur because of a user's program.
43 ///
44 /// For completness they are reported.
45 pub fn q_as_bool<Q>(&self, sink: &mut Q) -> bool
46 where
47 Q: QuirkSink<SValueToBoolQ>,
48 {
49 match self {
50 Self::Text(t) => {
51 if t.as_ref() == "" {
52 sink.put(SValueToBoolQ::EmptyStringTreatedAsFalse);
53 false
54 } else if t.as_ref() == "false" {
55 false
56 } else if t.as_ref() == "true" {
57 true
58 } else {
59 sink.put(SValueToBoolQ::NonEmptyStringTreatedAsTrue);
60 true
61 }
62 }
63 Self::Bool(b) => *b,
64 Self::Int(0) | Self::Float(0.0) => {
65 sink.put(SValueToBoolQ::ZeroToFalse);
66 false
67 }
68 Self::Int(1) | Self::Float(1.0) => {
69 sink.put(SValueToBoolQ::OneToTrue);
70 true
71 }
72 Self::Int(i) => {
73 sink.put(SValueToBoolQ::IntToBoolNotLossless(*i));
74 true
75 }
76 Self::Float(f) => {
77 sink.put(SValueToBoolQ::FloatToBoolNotLossless(*f));
78 true
79 }
80 }
81 }
82}