use std::fmt; use serde::Deserialize; use crate::domain::entity_type::EntityType; /// An image associated with an entity (roaster, roast, gear, or cafe). pub struct EntityImage { pub entity_type: EntityType, pub entity_id: i64, pub content_type: String, pub image_data: Vec, pub thumbnail_data: Vec, } /// Wrapper for image data URLs that redacts content in `Debug` output, /// allowing payloads to be traced without logging raw base64 image data. #[derive(Default, Deserialize)] #[serde(transparent)] pub struct ImageData(Option); impl ImageData { pub fn into_inner(self) -> Option { self.0 } pub fn as_deref(&self) -> Option<&str> { self.0.as_deref() } pub fn take(&mut self) -> Option { self.0.take() } pub fn cloned(&self) -> Option { self.0.clone() } } impl fmt::Debug for ImageData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.0 { Some(_) => write!(f, "Some()"), None => write!(f, "None"), } } } #[cfg(test)] mod tests { use super::*; #[test] fn image_data_debug_redacts_some() { let data: ImageData = serde_json::from_str(r#""data:image/png;base64,abc""#).unwrap(); assert_eq!(format!("{data:?}"), "Some()"); } #[test] fn image_data_debug_shows_none() { let data = ImageData::default(); assert_eq!(format!("{data:?}"), "None"); } }