data.rs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. use serde::Deserialize;
  2. use serde_yaml::Value;
  3. use crate::errors::IncompleteMappingError;
  4. use crate::image::{Image, Pixel};
  5. use std::collections::{HashMap, HashSet};
  6. #[derive(Deserialize, Debug)]
  7. pub struct Mapping(pub HashMap<Pixel, Option<ColorEntry>>);
  8. #[derive(Deserialize, Debug)]
  9. pub struct ColorEntry {
  10. pub color: Pixel,
  11. pub name: String,
  12. pub symbol: String,
  13. }
  14. impl ColorEntry {
  15. fn from_entry(
  16. entry: HashMap<String, Value>,
  17. ) -> Result<(Pixel, Option<ColorEntry>), Box<dyn std::error::Error>> {
  18. let color = match entry.get("color") {
  19. Some(Value::Sequence(v)) => {
  20. let r = v[0].as_u64().unwrap().try_into().unwrap();
  21. let g = v[1].as_u64().unwrap().try_into().unwrap();
  22. let b = v[2].as_u64().unwrap().try_into().unwrap();
  23. (r, g, b)
  24. }
  25. _ => panic!("Missing `color` in entry"),
  26. };
  27. if let Some(_) = entry.get("blank") {
  28. return Ok((color, None));
  29. }
  30. let name = entry["name"].as_str().unwrap().to_owned();
  31. let symbol = entry["symbol"].as_str().unwrap().to_owned();
  32. Ok((
  33. color,
  34. Some(ColorEntry {
  35. color,
  36. name,
  37. symbol,
  38. }),
  39. ))
  40. }
  41. }
  42. impl Mapping {
  43. pub fn load(
  44. path: impl AsRef<std::path::Path>,
  45. img: &Image,
  46. ) -> Result<Mapping, Box<dyn std::error::Error>> {
  47. let path = path.as_ref().to_path_buf();
  48. let data: Vec<HashMap<String, Value>> =
  49. serde_yaml::from_reader(std::fs::File::open(&path)?)?;
  50. // do validation to make sure all pixel colors are handled
  51. let color_map = data
  52. .into_iter()
  53. .map(|entry| {
  54. let (c, e) = ColorEntry::from_entry(entry)?;
  55. Ok((c, e))
  56. })
  57. .collect::<Result<HashMap<Pixel, Option<ColorEntry>>, Box<dyn std::error::Error>>>()?;
  58. let all_image_colors = img
  59. .iter()
  60. .map(|(_, color)| color)
  61. .collect::<HashSet<Pixel>>();
  62. let missing_colors = all_image_colors
  63. .into_iter()
  64. .filter(|c| !color_map.contains_key(&c))
  65. .collect::<Vec<Pixel>>();
  66. if !missing_colors.is_empty() {
  67. return Err(Box::new(IncompleteMappingError {
  68. path,
  69. missing_colors,
  70. }));
  71. }
  72. Ok(Mapping(color_map))
  73. }
  74. pub fn lookup(&self, color: Pixel) -> &str {
  75. if let Some(ref e) = self.0[&color] {
  76. &e.symbol
  77. } else {
  78. ""
  79. }
  80. }
  81. }
  82. #[derive(Deserialize)]
  83. pub struct Config {
  84. pub grid_every: u32,
  85. pub line_weight: f64,
  86. pub major_line_weight: f64,
  87. pub grid_size: f64,
  88. pub font: String,
  89. }
  90. impl Config {
  91. pub fn scale(&self, n: u32) -> f64 {
  92. n as f64 * self.grid_size
  93. }
  94. }
  95. impl Default for Config {
  96. fn default() -> Config {
  97. Config {
  98. grid_every: 10,
  99. line_weight: 1.0,
  100. major_line_weight: 3.0,
  101. grid_size: 24.0,
  102. font: "Fira Sans 12".to_string(),
  103. }
  104. }
  105. }