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
use serde::{Serialize, Deserialize, de, Serializer, Deserializer};
use std::{fmt, ops::{Index, IndexMut}};

use crate::{Color, LIGHTHOUSE_ROWS, LIGHTHOUSE_COLS, Pos, LIGHTHOUSE_RECT, LIGHTHOUSE_SIZE};

/// An 'image' to be displayed on the lighthouse.
/// The pixels are stored in row-major order.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Frame {
    pixels: [Color; LIGHTHOUSE_SIZE],
}

impl Frame {
    /// Creates a new empty `Frame`.
    pub fn empty() -> Self {
        Self::fill(Color::BLACK)
    }

    /// Creates a new `Frame` from the given pixels in
    /// row-major order.
    pub fn new(pixels: [Color; LIGHTHOUSE_SIZE]) -> Self {
        Self { pixels }
    }

    /// Creates a new uniformly colored `Frame`.
    pub fn fill(color: Color) -> Self {
        Self { pixels: [color; LIGHTHOUSE_SIZE] }
    }

    /// Creates a new `Frame` from the given generator function
    /// that associates each position of the form `(x, y)` with a
    /// color.
    pub fn generate(f: impl Fn(usize, usize) -> Color) -> Self {
        let mut frame = Self::empty();
        for y in 0..LIGHTHOUSE_ROWS {
            for x in 0..LIGHTHOUSE_COLS {
                frame.set(x, y, f(x, y));
            }
        }
        frame
    }

    /// Fetches the pixel at the given position.
    pub fn get(&self, x: usize, y: usize) -> Color {
        self[Pos::new(x as i32, y as i32)]
    }

    /// Sets the given pixel to the given color.
    pub fn set(&mut self, x: usize, y: usize, color: Color) {
        self[Pos::new(x as i32, y as i32)] = color;
    }
}

impl Index<Pos> for Frame {
    type Output = Color;

    fn index(&self, pos: Pos) -> &Color {
        &self.pixels[LIGHTHOUSE_RECT.index_of(pos)]
    }
}

impl IndexMut<Pos> for Frame {
    fn index_mut(&mut self, pos: Pos) -> &mut Color {
        &mut self.pixels[LIGHTHOUSE_RECT.index_of(pos)]
    }
}

impl Serialize for Frame {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer {
        let bytes: Vec<u8> = self.pixels.iter()
            .flat_map(|c| [c.red, c.green, c.blue].into_iter())
            .collect();
        serializer.serialize_bytes(&bytes)
    }
}

impl<'de> Deserialize<'de> for Frame {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de> {
        deserializer.deserialize_bytes(FrameBytesVisitor)
    }
}

struct FrameBytesVisitor;

impl<'de> de::Visitor<'de> for FrameBytesVisitor {
    type Value = Frame;

    fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "a byte array whose length is a multiple of 3")
    }

    fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
        where E: de::Error {
        if v.len() % 3 == 0 {
            Ok(Frame {
                pixels: v
                    .chunks(3)
                    .map(|c| match c {
                        &[r, g, b] => Color::new(r, g, b),
                        _ => unreachable!(),
                    })
                    .collect::<Vec<_>>()
                    .try_into()
                    .map(Ok)
                    .unwrap_or_else(|_| Err(E::custom("Could not decode into pixels array".to_owned())))?
            })
        } else {
            Err(E::custom(format!("{} (length of byte array) is not a multiple of 3", v.len())))
        }
    }
}