clerk/
entry_mode.rs

1bitflags! {
2    struct EntryModeFlags: u8 {
3        const ENTRY_MODE            = 0b0000_0100;
4        const CURSOR_MOVE_INCREMENT = 0b0000_0010;
5        const DISPLAY_SHIFT_ON      = 0b0000_0001;
6        const CURSOR_MOVE_DECREMENT = 0b0000_0000;
7        const DISPLAY_SHIFT_OFF     = 0b0000_0000;
8    }
9}
10
11/// Enumeration of possible methods to move.
12#[derive(Clone, Copy)]
13pub enum MoveDirection {
14    /// Moves right.
15    Increment,
16    /// Moves left.
17    Decrement,
18}
19
20impl From<MoveDirection> for EntryModeFlags {
21    fn from(direction: MoveDirection) -> Self {
22        match direction {
23            MoveDirection::Increment => EntryModeFlags::CURSOR_MOVE_INCREMENT,
24            MoveDirection::Decrement => EntryModeFlags::CURSOR_MOVE_DECREMENT,
25        }
26    }
27}
28
29/// Enumeration to set display shift.
30#[derive(Clone, Copy)]
31pub enum DisplayShift {
32    On,
33    Off,
34}
35
36impl From<DisplayShift> for EntryModeFlags {
37    fn from(shift: DisplayShift) -> Self {
38        match shift {
39            DisplayShift::On => EntryModeFlags::DISPLAY_SHIFT_ON,
40            DisplayShift::Off => EntryModeFlags::DISPLAY_SHIFT_OFF,
41        }
42    }
43}
44
45/// A struct for creating display entry mode settings.
46pub struct EntryModeBuilder {
47    move_direction: MoveDirection,
48    display_shift: DisplayShift,
49}
50
51impl EntryModeBuilder {
52    /// Sets the direction the read/write cursor is moved when a character code is written to or
53    /// read from the display.
54    pub fn set_move_direction(&mut self, direction: MoveDirection) -> &mut Self {
55        self.move_direction = direction;
56        self
57    }
58
59    /// Sets the display shift, which will be performed on character write, either `On` or `Off`.
60    ///
61    /// If display shift is enabled, it will seem as if the cursor does not move but the display
62    /// does.
63    ///
64    /// **Note:** The display does not shift when reading.
65    pub fn set_display_shift(&mut self, shift: DisplayShift) -> &mut Self {
66        self.display_shift = shift;
67        self
68    }
69
70    pub(crate) fn build_command(&self) -> u8 {
71        let mut cmd = EntryModeFlags::ENTRY_MODE;
72
73        cmd |= EntryModeFlags::from(self.move_direction);
74        cmd |= EntryModeFlags::from(self.display_shift);
75
76        cmd.bits()
77    }
78}
79
80impl Default for EntryModeBuilder {
81    /// Make a new `EntryModeBuilder` with the default settings described below.
82    ///
83    /// The default settings are:
84    ///
85    ///  - **move direction:**
86    ///     - `Increment`
87    ///  - **display_shift:**
88    ///     - `Off`
89    fn default() -> Self {
90        Self {
91            move_direction: MoveDirection::Increment,
92            display_shift: DisplayShift::Off,
93        }
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100
101    const ENTRY_MODE_FLAG: u8 = 0b0000_0100;
102    const MOVE_DIRECTION_FLAG: u8 = 0b0000_0010;
103    const DISPLAY_SHIFT_FLAG: u8 = 0b0000_0001;
104
105    fn has_bit(value: u8, bitmask: u8) -> bool {
106        value & bitmask == bitmask
107    }
108
109    #[test]
110    fn entry_mode_flag() {
111        let b = EntryModeBuilder::default();
112        let cmd = b.build_command();
113
114        assert!(has_bit(cmd, ENTRY_MODE_FLAG));
115    }
116
117    #[test]
118    fn default_move_direction() {
119        let b = EntryModeBuilder::default();
120        let cmd = b.build_command();
121
122        assert!(has_bit(cmd, MOVE_DIRECTION_FLAG));
123    }
124
125    #[test]
126    fn set_move_direction() {
127        let mut b = EntryModeBuilder::default();
128
129        let cmd = b.build_command();
130        assert!(has_bit(cmd, MOVE_DIRECTION_FLAG));
131
132        b.set_move_direction(MoveDirection::Decrement);
133
134        let cmd = b.build_command();
135        assert_eq!(has_bit(cmd, MOVE_DIRECTION_FLAG), false);
136    }
137
138    #[test]
139    fn default_display_shift() {
140        let b = EntryModeBuilder::default();
141        let cmd = b.build_command();
142
143        assert_eq!(has_bit(cmd, DISPLAY_SHIFT_FLAG), false);
144    }
145
146    #[test]
147    fn set_display_shift() {
148        let mut b = EntryModeBuilder::default();
149
150        let cmd = b.build_command();
151        assert_eq!(has_bit(cmd, DISPLAY_SHIFT_FLAG), false);
152
153        b.set_display_shift(DisplayShift::On);
154
155        let cmd = b.build_command();
156        assert!(has_bit(cmd, DISPLAY_SHIFT_FLAG));
157    }
158}