|
1 | 1 | use eframe::epaint::ColorImage; |
2 | 2 | use egui_extras::RetainedImage; |
3 | | -use serde::{ |
4 | | - self, |
5 | | - de::{Error as SerdeError, SeqAccess, Visitor}, |
6 | | - ser::SerializeStruct, |
7 | | - Deserialize, Deserializer, Serialize, Serializer, |
8 | | -}; |
9 | | -use std::fmt; |
| 3 | +use serde::{self, Deserialize, Serialize}; |
| 4 | +use std::fmt::{self, Debug}; |
10 | 5 |
|
| 6 | +#[derive(Serialize, Deserialize)] |
11 | 7 | pub struct Exercise { |
| 8 | + #[serde(skip)] |
12 | 9 | pub image: Option<RetainedImage>, |
13 | 10 | original_image: Option<(usize, usize, Vec<u8>)>, |
14 | 11 | pub title: String, |
@@ -46,106 +43,27 @@ impl Exercise { |
46 | 43 | img.pixels.iter().map(|p| p.to_array()).flatten().collect(), |
47 | 44 | )); |
48 | 45 | } |
49 | | -} |
50 | | - |
51 | | -impl Serialize for Exercise { |
52 | | - fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
53 | | - where |
54 | | - S: Serializer, |
55 | | - { |
56 | | - let mut state = serializer.serialize_struct("Exercise", 4)?; |
57 | | - |
58 | | - // Ensure title is valid UTF-8 |
59 | | - let title = match String::from_utf8(self.title.clone().into_bytes()) { |
60 | | - Ok(valid_title) => valid_title, |
61 | | - Err(_) => { |
62 | | - // Handle the case where the title is not valid UTF-8, e.g., by replacing invalid sequences with � (U+FFFD) |
63 | | - String::from_utf8_lossy(&self.title.as_bytes()).to_string() |
64 | | - } |
65 | | - }; |
66 | | - |
67 | | - state.serialize_field("title", &title)?; |
68 | | - if let Some(img) = &self.original_image { |
69 | | - state.serialize_field("original_image", img)?; |
70 | | - } |
71 | | - state.serialize_field("code", &self.code)?; |
72 | | - |
73 | | - state.end() |
74 | | - } |
75 | | -} |
76 | | - |
77 | | -impl<'de> Deserialize<'de> for Exercise { |
78 | | - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
79 | | - where |
80 | | - D: Deserializer<'de>, |
81 | | - { |
82 | | - struct ExerciseVisitor; |
83 | | - |
84 | | - impl<'de> Visitor<'de> for ExerciseVisitor { |
85 | | - type Value = Exercise; |
86 | 46 |
|
87 | | - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
88 | | - formatter.write_str("an Exercise in binary format") |
89 | | - } |
90 | | - |
91 | | - fn visit_seq<A>(self, mut seq: A) -> Result<Exercise, A::Error> |
92 | | - where |
93 | | - A: SeqAccess<'de>, |
94 | | - { |
95 | | - let title: String = seq |
96 | | - .next_element()? |
97 | | - .ok_or_else(|| A::Error::invalid_length(0, &self))?; |
98 | | - let original_image: (usize, usize, Vec<u8>) = seq |
99 | | - .next_element()? |
100 | | - .ok_or_else(|| A::Error::invalid_length(1, &self))?; |
101 | | - let code: String = seq |
102 | | - .next_element()? |
103 | | - .ok_or_else(|| A::Error::invalid_length(2, &self))?; |
104 | | - |
105 | | - Ok(Exercise::new( |
106 | | - &title, |
107 | | - Some(ColorImage::from_rgba_unmultiplied( |
108 | | - [original_image.0 as usize, original_image.1 as usize], |
109 | | - &original_image.2, |
110 | | - )), |
111 | | - code, |
112 | | - )) |
| 47 | + pub fn get_cover(&mut self) -> Option<&RetainedImage> { |
| 48 | + match self.image { |
| 49 | + Some(ref img) => Some(img), |
| 50 | + None => { |
| 51 | + if let Some(img) = &self.original_image { |
| 52 | + self.set_cover(ColorImage::from_rgba_premultiplied([img.0, img.1], &img.2)); |
| 53 | + self.image.as_ref() |
| 54 | + } else { |
| 55 | + None |
| 56 | + } |
113 | 57 | } |
114 | 58 | } |
115 | | - |
116 | | - deserializer.deserialize_tuple(3, ExerciseVisitor) |
117 | 59 | } |
118 | 60 | } |
119 | 61 |
|
120 | | -// Custom deserializer for the tuple (String, Vec<Exercise>) |
121 | | -#[allow(dead_code)] |
122 | | -fn deserialize_tuple<'de, D>(deserializer: D) -> Result<(String, Vec<Exercise>), D::Error> |
123 | | -where |
124 | | - D: Deserializer<'de>, |
125 | | -{ |
126 | | - struct TupleVisitor; |
127 | | - |
128 | | - impl<'de> Visitor<'de> for TupleVisitor { |
129 | | - type Value = (String, Vec<Exercise>); |
130 | | - |
131 | | - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
132 | | - formatter.write_str("a tuple (String, Vec<Exercise>) in binary format") |
133 | | - } |
134 | | - |
135 | | - fn visit_seq<A>(self, mut seq: A) -> Result<(String, Vec<Exercise>), A::Error> |
136 | | - where |
137 | | - A: SeqAccess<'de>, |
138 | | - { |
139 | | - let key: String = seq |
140 | | - .next_element()? |
141 | | - .ok_or_else(|| A::Error::invalid_length(0, &self))?; |
142 | | - let value: Vec<Exercise> = seq |
143 | | - .next_element()? |
144 | | - .ok_or_else(|| A::Error::invalid_length(1, &self))?; |
145 | | - |
146 | | - Ok((key, value)) |
147 | | - } |
| 62 | +impl Debug for Exercise { |
| 63 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 64 | + f.debug_struct("Exercise") |
| 65 | + .field("title", &self.title) |
| 66 | + .field("code", &self.code) |
| 67 | + .finish() |
148 | 68 | } |
149 | | - |
150 | | - deserializer.deserialize_tuple(2, TupleVisitor) |
151 | 69 | } |
0 commit comments