file_metadata.rs (3546B)
1 #[cfg(not(feature = "std"))] 2 use alloc::{string::String, vec::Vec}; 3 4 use crate::social::{RadrootsSocialMediaDimensions, RadrootsSocialMediaThumbnail}; 5 6 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 7 #[derive(Clone, Debug)] 8 pub struct RadrootsFileMetadata { 9 pub url: String, 10 pub mime_type: String, 11 pub sha256: String, 12 #[cfg_attr( 13 feature = "serde", 14 serde(default, skip_serializing_if = "Option::is_none") 15 )] 16 pub original_sha256: Option<String>, 17 #[cfg_attr( 18 feature = "serde", 19 serde(default, skip_serializing_if = "Option::is_none") 20 )] 21 pub size: Option<u64>, 22 #[cfg_attr( 23 feature = "serde", 24 serde(default, skip_serializing_if = "Option::is_none") 25 )] 26 pub dimensions: Option<RadrootsSocialMediaDimensions>, 27 #[cfg_attr( 28 feature = "serde", 29 serde(default, skip_serializing_if = "Option::is_none") 30 )] 31 pub blurhash: Option<String>, 32 #[cfg_attr( 33 feature = "serde", 34 serde(default, skip_serializing_if = "Option::is_none") 35 )] 36 pub thumbnails: Option<Vec<RadrootsSocialMediaThumbnail>>, 37 #[cfg_attr( 38 feature = "serde", 39 serde(default, skip_serializing_if = "Option::is_none") 40 )] 41 pub summary: Option<String>, 42 #[cfg_attr( 43 feature = "serde", 44 serde(default, skip_serializing_if = "Option::is_none") 45 )] 46 pub alt: Option<String>, 47 #[cfg_attr( 48 feature = "serde", 49 serde(default, skip_serializing_if = "Option::is_none") 50 )] 51 pub fallback: Option<String>, 52 #[cfg_attr( 53 feature = "serde", 54 serde(default, skip_serializing_if = "Option::is_none") 55 )] 56 pub magnet: Option<String>, 57 #[cfg_attr( 58 feature = "serde", 59 serde(default, skip_serializing_if = "Option::is_none") 60 )] 61 pub content_hashes: Option<Vec<String>>, 62 #[cfg_attr( 63 feature = "serde", 64 serde(default, skip_serializing_if = "Option::is_none") 65 )] 66 pub services: Option<Vec<String>>, 67 #[cfg_attr( 68 feature = "serde", 69 serde(default, skip_serializing_if = "Option::is_none") 70 )] 71 pub content: Option<String>, 72 } 73 74 #[cfg(all(test, feature = "std", feature = "serde"))] 75 mod tests { 76 use super::*; 77 78 #[test] 79 fn file_metadata_represents_required_nip94_fields() { 80 let metadata = RadrootsFileMetadata { 81 url: "https://example.test/file.jpg".to_string(), 82 mime_type: "image/jpeg".to_string(), 83 sha256: "a".repeat(64), 84 original_sha256: Some("b".repeat(64)), 85 size: Some(1024), 86 dimensions: Some(RadrootsSocialMediaDimensions { 87 width: 640, 88 height: 480, 89 }), 90 blurhash: None, 91 thumbnails: None, 92 summary: Some("field image".to_string()), 93 alt: Some("rows of lettuce".to_string()), 94 fallback: None, 95 magnet: Some("magnet:?xt=urn:btih:abc".to_string()), 96 content_hashes: Some(vec!["sha256:a".to_string()]), 97 services: Some(vec!["https://media.example.test".to_string()]), 98 content: Some("caption".to_string()), 99 }; 100 101 assert_eq!(metadata.mime_type, "image/jpeg"); 102 assert_eq!(metadata.sha256.len(), 64); 103 assert_eq!(metadata.dimensions.expect("dimensions").width, 640); 104 assert!(metadata.magnet.expect("magnet").starts_with("magnet:")); 105 assert_eq!(metadata.services.expect("services").len(), 1); 106 } 107 }