1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
use super::Serial;

//fmt::{Binary, Display, LowerExp, LowerHex, Octal, Write},
pub use core::mem::size_of;
pub use heapless::String;
pub use ufmt::{uDisplay, uDisplayHex, uwrite};
pub use ufmt_write::uWrite;

/// Trait to allow implementing specific `Serial::write` behavior for types.
pub trait SerialWritable {
    /// Takes a reference to the instance of this type and writes it to the `Serial` connection.
    fn write_to_serial(&self);
}

impl SerialWritable for char {
    /// Writes a single character to the UART connection.
    ///
    /// Example:
    /// ```rust
    /// Serial::write('R');
    /// Serial::write('P');
    /// Serial::write('6');
    /// Serial::write('\n'); // '\n' is a special code for the "new line" character!
    /// Serial::write('0'); // the ASCII character '0'
    /// Serial::write(48 as char); // 48 is numeric ASCII code for '0'
    /// Serial::write(49 as char); // '1'
    /// Serial::write(50 as char); // '2'
    /// Serial::write(51 as char); // '3'
    /// ```
    ///
    /// This example would send:
    /// ```
    /// RP6
    /// 00123
    /// ```
    /// via the robot's serial connection.
    fn write_to_serial(&self) {
        Serial::write_raw(*self as u8);
    }
}

impl SerialWritable for &str {
    /// Write text to the `Serial` connection.
    fn write_to_serial(&self) {
        for c in self.chars() {
            Serial::write(c);
        }
    }
}

/// Trait to allow instantiation and passing as `&str` for a type.
pub trait StringType: uWrite {
    /// Instantiate the `StringType`.
    fn new() -> Self;
    /// Allow passing the `StringType` as `&str`.
    fn as_str(&self) -> &str;
}

impl<const N: usize> StringType for String<N> {
    fn new() -> Self {
        String::<N>::new()
    }

    fn as_str(&self) -> &str {
        self.as_str()
    }
}

/// Trait to allow implementing specific `Serial::write_dec` behavior for types.
pub trait SerialWritableDecimal: uDisplay {
    type DecimalString: StringType;

    /// Format the given number as decimal and write it to the `Serial` connection.
    fn write_to_serial_as_dec(&self) {
        let mut buffer = Self::DecimalString::new();
        let _ = uwrite!(&mut buffer, "{}", *self);
        Serial::write(StringType::as_str(&buffer));
    }
}

/// Default implementation for numbers is to format them as decimal.
impl<T: SerialWritableDecimal> SerialWritable for T {
    /// Default formatter: format numbers as decimal.
    fn write_to_serial(&self) {
        self.write_to_serial_as_dec();
    }
}

/*
/// Trait to allow implementing specific `Serial::write_bin` behavior for types.
pub trait SerialWritableBinary: Binary {
    type BinaryString: StringType;

    /// Format the given number as binary and write it to the `Serial` connection.
    fn write_to_serial_as_bin(&self) {
        let mut buffer = Self::BinaryString::new();
        let _ = write!(&mut buffer, "{:b}", self);
        Serial::write(StringType::as_str(&buffer));
    }
}
*/

/*
/// Trait to allow implementing specific `Serial::write_exp` behavior for types.
pub trait SerialWritableExponential: LowerExp {
    type ExponentialString: StringType;

    /// Format the given number as decimal and write it to the `Serial` connection.
    fn write_to_serial_as_exp(&self) {
        let mut buffer = Self::ExponentialString::new();
        let _ = write!(&mut buffer, "{:e}", self);
        Serial::write(StringType::as_str(&buffer));
    }
}
*/

/// Trait to allow implementing specific `Serial::write_hex` behavior for types.
pub trait SerialWritableHexadecimal: uDisplayHex {
    type HexadecimalString: StringType;

    /// Format the given number as hexadecimal and write it to the `Serial` connection.
    fn write_to_serial_as_hex(&self) {
        let mut buffer = Self::HexadecimalString::new();
        let _ = uwrite!(&mut buffer, "{:x}", *self);
        Serial::write(StringType::as_str(&buffer));
    }
}

/*
/// Trait to allow implementing specific `Serial::write_oct` behavior for types.
pub trait SerialWritableOctal: Octal {
    type OctalString: StringType;

    /// Format the given number as octal and write it to the `Serial` connection.
    fn write_to_serial_as_oct(&self) {
        let mut buffer = Self::OctalString::new();
        let _ = write!(&mut buffer, "{:o}", self);
        Serial::write(StringType::as_str(&buffer));
    }
}
*/

/// Implement the traits for `Binary`, `Decimal`, `Hexadecimal` and `Octal` formatting of a number.
macro_rules! impl_serial_writable_num {
    // default: use 4 * bytesize as $size_dec (accounting for signed types)
    ($type: ty $(,)?) => {
        impl_serial_writable_num!($type, 4 * ::core::mem::size_of::<$type>());
    };
    // default: use 3 * bytesize as $size_oct
    ($type: ty, $size_dec: expr $(,)?) => {
        impl_serial_writable_num!($type, $size_dec, 3 * ::core::mem::size_of::<$type>());
    };
    // implement traits for Binary, Decimal, Hexadecimal and Octal
    ($type: ty, $size_dec: expr, $size_oct: expr $(,)?) => {
        //impl_serial_writable_num!(@impl $type, Binary, 8 * ::core::mem::size_of::<$type>());
        impl_serial_writable_num!(@impl $type, Decimal, $size_dec);
        impl_serial_writable_num!(@impl $type, Hexadecimal, 2 * ::core::mem::size_of::<$type>());
        //impl_serial_writable_num!(@impl $type, Octal, $size_oct);
    };
    // implement the trait `SerialWritable{$base_ident}` for `$type`.
    (@impl $type: ty, $base_name: ident, $size: expr) => {
        paste::paste! {
            impl [<SerialWritable $base_name>] for $type {
                type [<$base_name String>] = String<{ $size }>;
            }
        }
    };
}

impl_serial_writable_num!(u8);
impl_serial_writable_num!(u16);
impl_serial_writable_num!(u32);
impl_serial_writable_num!(u64);
impl_serial_writable_num!(u128);
impl_serial_writable_num!(usize);
impl_serial_writable_num!(i8);
impl_serial_writable_num!(i16);
impl_serial_writable_num!(i32);
impl_serial_writable_num!(i64);
impl_serial_writable_num!(i128);
impl_serial_writable_num!(isize);

/*
/// Implement the trait for `Decimal` formatting of a number.
macro_rules! impl_serial_writable_float {
    ($type: ty, $size_in_chars: expr) => {
        impl_serial_writable_num!(@impl $type, Decimal, $size_in_chars);
        impl_serial_writable_num!(@impl $type, Exponential, $size_in_chars);
    };
}

impl_serial_writable_float!(f32, 100);
impl_serial_writable_float!(f64, 100);
*/