diff options
author | Griffin Smith <root@gws.fyi> | 2019-07-14T18·29-0400 |
---|---|---|
committer | Griffin Smith <root@gws.fyi> | 2019-07-14T18·29-0400 |
commit | e7ad87c7301f266dece36e7558c0f212e370aac6 (patch) | |
tree | 7da150d5648cc0b17d973bf4a30673f36b20be82 /src/display | |
parent | 081146da30bcf1a17d9533c3dc9c735a3a558165 (diff) |
Add (statically-included) entity raws
Add a system for statically-included entity raws (which necessitated making a deserializable existential Color struct) and test it out by initializing the game (for now) with a single on-screen gormlak.
Diffstat (limited to 'src/display')
-rw-r--r-- | src/display/color.rs | 149 | ||||
-rw-r--r-- | src/display/mod.rs | 5 |
2 files changed, 152 insertions, 2 deletions
diff --git a/src/display/color.rs b/src/display/color.rs new file mode 100644 index 000000000000..7de1f124b704 --- /dev/null +++ b/src/display/color.rs @@ -0,0 +1,149 @@ +use serde::de::{self, Unexpected, Visitor}; +use std::fmt; +use std::marker::PhantomData; +use termion::color; + +#[derive(Debug)] +pub struct Color(Box<dyn color::Color>); + +unsafe impl Sync for Color {} +unsafe impl Send for Color {} + +impl Color { + pub fn new<C: color::Color + 'static>(c: C) -> Self { + Color(Box::new(c)) + } +} + +impl color::Color for Color { + fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.write_fg(f) + } + + fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.write_bg(f) + } +} + +impl<'a> color::Color for &'a Color { + fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.write_fg(f) + } + + fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.write_bg(f) + } +} + +pub struct ColorVisitor { + marker: PhantomData<fn() -> Color>, +} + +impl ColorVisitor { + fn new() -> Self { + ColorVisitor { + marker: PhantomData, + } + } +} + +impl<'de> Visitor<'de> for ColorVisitor { + type Value = Color; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("A color") + } + + fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> + where + E: de::Error, + { + match v.to_lowercase().as_ref() { + "black" => Ok(Color(Box::new(color::Black))), + "blue" => Ok(Color(Box::new(color::Blue))), + "cyan" => Ok(Color(Box::new(color::Cyan))), + "green" => Ok(Color(Box::new(color::Green))), + "light black" | "light_black" => { + Ok(Color(Box::new(color::LightBlack))) + } + "light blue" | "light_blue" => { + Ok(Color(Box::new(color::LightBlue))) + } + "light cyan" | "light_cyan" => { + Ok(Color(Box::new(color::LightCyan))) + } + "light green" | "light_green" => { + Ok(Color(Box::new(color::LightGreen))) + } + "light magenta" | "light_magenta" => { + Ok(Color(Box::new(color::LightMagenta))) + } + "light red" | "light_red" => Ok(Color(Box::new(color::LightRed))), + "light white" | "light_white" => { + Ok(Color(Box::new(color::LightWhite))) + } + "light yellow" | "light_yellow" => { + Ok(Color(Box::new(color::LightYellow))) + } + "magenta" => Ok(Color(Box::new(color::Magenta))), + "magenta" => Ok(Color(Box::new(color::Magenta))), + "red" => Ok(Color(Box::new(color::Red))), + "white" => Ok(Color(Box::new(color::White))), + "yellow" => Ok(Color(Box::new(color::Yellow))), + _ => Err(de::Error::invalid_value( + Unexpected::Str(v), + &"a valid color", + )), + } + } + + fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> + where + A: de::MapAccess<'de>, + { + let mut red = None; + let mut green = None; + let mut blue = None; + while let Some((k, v)) = map.next_entry()? { + match k { + "red" => { + red = Some(v); + } + "green" => { + green = Some(v); + } + "blue" => { + blue = Some(v); + } + _ => { + return Err(de::Error::unknown_field( + k, + &["red", "green", "blue"], + )); + } + } + } + + match (red, green, blue) { + (Some(r), Some(g), Some(b)) => { + Ok(Color(Box::new(color::Rgb(r, g, b)))) + } + (None, _, _) => Err(de::Error::missing_field("red")), + (_, None, _) => Err(de::Error::missing_field("green")), + (_, _, None) => Err(de::Error::missing_field("blue")), + } + } + + fn visit_u8<E: de::Error>(self, v: u8) -> Result<Self::Value, E> { + Ok(Color(Box::new(color::AnsiValue(v)))) + } +} + +impl<'de> serde::Deserialize<'de> for Color { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_any(ColorVisitor::new()) + } +} diff --git a/src/display/mod.rs b/src/display/mod.rs index 9e15a0d97d62..3e30200ac723 100644 --- a/src/display/mod.rs +++ b/src/display/mod.rs @@ -1,3 +1,4 @@ +pub mod color; pub mod draw_box; pub mod utils; pub mod viewport; @@ -17,13 +18,13 @@ pub trait Draw: Positioned { fn do_draw(&self, out: &mut Write) -> io::Result<()>; } -impl<T : Draw> Draw for &T { +impl<T: Draw> Draw for &T { fn do_draw(&self, out: &mut Write) -> io::Result<()> { (**self).do_draw(out) } } -impl<T : Draw> Draw for Box<T> { +impl<T: Draw> Draw for Box<T> { fn do_draw(&self, out: &mut Write) -> io::Result<()> { (**self).do_draw(out) } |