From 97f2678563e6ca997ea33d7befe38ab2acfa01a9 Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Sat, 14 Dec 2019 03:23:46 +0100 Subject: add preliminary support for user configurations --- src/useropts.rs | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 src/useropts.rs (limited to 'src/useropts.rs') diff --git a/src/useropts.rs b/src/useropts.rs new file mode 100644 index 0000000..e6de8de --- /dev/null +++ b/src/useropts.rs @@ -0,0 +1,127 @@ +//! Support for loading user defined rendering options. +//! +//! User options are given in a toml file, for example +//! +//! ```toml +//! skill_size = 20 +//! ``` +//! +//! The file is automatically deserialized by serde, so all fields defined in +//! [`UserOptions`](struct.UserOptions.html) can be used. +use image::Rgba; +use rusttype::Font; +use serde::{Deserialize, Serialize}; +use std::{error::Error, fmt, fs, io, path::Path}; + +use super::render::{Alignment, RenderOptions}; + +/// Error that can occur during loading or converting user options. +#[derive(Debug)] +pub enum ConfigError { + Io(io::Error), + Serialization(toml::de::Error), + Font(rusttype::Error), +} + +error_froms! { + ConfigError, + err: io::Error => ConfigError::Io(err), + err: toml::de::Error => ConfigError::Serialization(err), + err: rusttype::Error => ConfigError::Font(err), +} + +impl fmt::Display for ConfigError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "ConfigError: ")?; + match *self { + ConfigError::Io(_) => write!(f, "input/output error"), + ConfigError::Serialization(_) => write!(f, "serialization error"), + ConfigError::Font(_) => write!(f, "could not load the font"), + } + } +} + +impl Error for ConfigError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + match *self { + ConfigError::Io(ref err) => Some(err), + ConfigError::Serialization(ref err) => Some(err), + ConfigError::Font(ref err) => Some(err), + } + } +} + +macro_rules! maybe_take_from { + (from: $from:expr, to: $to:ident, $($field:ident,)*) => { + $( + if let Some(data) = $from.$field { + $to.$field = data; + } + )* + } +} + +/// A struct for deserializing user defined options. +/// +/// This is basically a struct containing the same fields, but optional. If a field is given, it +/// should override the corresponding field in +/// [`RenderOptions`](../render/struct.RenderOptions.html). +/// +/// Some fields require some pre-processing, as the proper type cannot be serialized (e.g. +/// `image::Rgba` for `background_color`). +#[derive(Debug, Serialize, Deserialize)] +pub struct UserOptions { + pub traitline_x_offset: Option, + pub trait_size: Option, + pub line_color: Option<[u8; 4]>, + pub line_height: Option, + pub text_size: Option, + pub background_color: Option<[u8; 4]>, + pub font_path: Option, + pub render_specialization_names: Option, + pub skill_alignment: Option, +} + +impl UserOptions { + /// Converts this `UserOptions` to a proper + /// [`RenderOptions`](../render/struct.RenderOptions.html). + pub fn convert(self) -> Result { + let mut result = RenderOptions::default(); + + if let Some(data) = self.background_color { + result.background_color = Rgba(data); + } + + if let Some(data) = self.line_color { + result.line_color = Rgba(data); + } + + if let Some(path) = self.font_path { + let data = fs::read(path)?; + let font = Font::from_bytes(data)?; + result.font = font; + } + + maybe_take_from! { + from: self, to: result, + traitline_x_offset, + trait_size, + line_height, + text_size, + render_specialization_names, + skill_alignment, + } + + Ok(result) + } +} + +/// Load user given options from the given file path. +/// +/// This is basically a convenience function around reading the data, deserializing it from toml +/// and returning [`UserOptions::convert`](struct.UserOptions.html#method.convert). +pub fn load_file>(path: P) -> Result { + let data = fs::read(path)?; + let opts = toml::from_slice::(&data)?; + opts.convert() +} -- cgit v1.2.3