1use crate::ptp::{AssociationType, DateTime, ObjectFormatCode, ObjectInfo as PtpObjectInfo};
4
5#[derive(Debug, Clone)]
7pub struct NewObjectInfo {
8 pub filename: String,
10 pub size: u64,
12 pub format: Option<ObjectFormatCode>,
14 pub modified: Option<DateTime>,
16}
17
18impl NewObjectInfo {
19 #[must_use]
21 pub fn file(filename: impl Into<String>, size: u64) -> Self {
22 let filename = filename.into();
23 let format = detect_format_from_filename(&filename);
24 Self {
25 filename,
26 size,
27 format: Some(format),
28 modified: None,
29 }
30 }
31
32 #[must_use]
34 pub fn folder(name: impl Into<String>) -> Self {
35 Self {
36 filename: name.into(),
37 size: 0,
38 format: Some(ObjectFormatCode::Association),
39 modified: None,
40 }
41 }
42
43 #[must_use]
45 pub fn with_format(filename: impl Into<String>, size: u64, format: ObjectFormatCode) -> Self {
46 Self {
47 filename: filename.into(),
48 size,
49 format: Some(format),
50 modified: None,
51 }
52 }
53
54 #[must_use]
56 pub fn with_modified(mut self, modified: DateTime) -> Self {
57 self.modified = Some(modified);
58 self
59 }
60
61 pub(crate) fn to_object_info(&self) -> PtpObjectInfo {
63 let format = self.format.unwrap_or(ObjectFormatCode::Undefined);
64 let is_folder = format == ObjectFormatCode::Association;
65
66 PtpObjectInfo {
67 format,
68 size: self.size,
69 filename: self.filename.clone(),
70 modified: self.modified,
71 association_type: if is_folder {
72 AssociationType::GenericFolder
73 } else {
74 AssociationType::None
75 },
76 ..Default::default()
77 }
78 }
79}
80
81fn detect_format_from_filename(filename: &str) -> ObjectFormatCode {
83 if let Some(ext) = filename.rsplit('.').next() {
84 ObjectFormatCode::from_extension(ext)
85 } else {
86 ObjectFormatCode::Undefined
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn test_new_object_info_file() {
96 let info = NewObjectInfo::file("test.mp3", 1000);
97 assert_eq!(info.filename, "test.mp3");
98 assert_eq!(info.size, 1000);
99 assert_eq!(info.format, Some(ObjectFormatCode::Mp3));
100 }
101
102 #[test]
103 fn test_new_object_info_folder() {
104 let info = NewObjectInfo::folder("Music");
105 assert_eq!(info.filename, "Music");
106 assert_eq!(info.size, 0);
107 assert_eq!(info.format, Some(ObjectFormatCode::Association));
108 }
109
110 #[test]
111 fn test_format_detection() {
112 assert_eq!(
113 detect_format_from_filename("song.mp3"),
114 ObjectFormatCode::Mp3
115 );
116 assert_eq!(
117 detect_format_from_filename("photo.jpg"),
118 ObjectFormatCode::Jpeg
119 );
120 assert_eq!(
121 detect_format_from_filename("video.mp4"),
122 ObjectFormatCode::Mp4Container
123 );
124 assert_eq!(
125 detect_format_from_filename("unknown.xyz"),
126 ObjectFormatCode::Undefined
127 );
128 }
129
130 #[test]
131 fn test_with_format() {
132 let info = NewObjectInfo::with_format("document.bin", 500, ObjectFormatCode::Executable);
133 assert_eq!(info.filename, "document.bin");
134 assert_eq!(info.size, 500);
135 assert_eq!(info.format, Some(ObjectFormatCode::Executable));
136 }
137
138 #[test]
139 fn test_with_modified() {
140 let dt = DateTime {
141 year: 2024,
142 month: 6,
143 day: 15,
144 hour: 10,
145 minute: 30,
146 second: 0,
147 };
148 let info = NewObjectInfo::file("test.txt", 100).with_modified(dt);
149 assert_eq!(info.modified, Some(dt));
150 }
151
152 #[test]
153 fn test_to_object_info_file() {
154 let info = NewObjectInfo::file("test.mp3", 1000);
155 let ptp_info = info.to_object_info();
156
157 assert_eq!(ptp_info.format, ObjectFormatCode::Mp3);
158 assert_eq!(ptp_info.size, 1000);
159 assert_eq!(ptp_info.filename, "test.mp3");
160 assert_eq!(ptp_info.association_type, AssociationType::None);
161 }
162
163 #[test]
164 fn test_to_object_info_folder() {
165 let info = NewObjectInfo::folder("Music");
166 let ptp_info = info.to_object_info();
167
168 assert_eq!(ptp_info.format, ObjectFormatCode::Association);
169 assert_eq!(ptp_info.size, 0);
170 assert_eq!(ptp_info.filename, "Music");
171 assert_eq!(ptp_info.association_type, AssociationType::GenericFolder);
172 }
173
174 #[test]
175 fn test_format_detection_case_insensitive() {
176 assert_eq!(
178 detect_format_from_filename("SONG.MP3"),
179 ObjectFormatCode::Mp3
180 );
181 assert_eq!(
182 detect_format_from_filename("Photo.JPG"),
183 ObjectFormatCode::Jpeg
184 );
185 }
186
187 #[test]
188 fn test_format_detection_no_extension() {
189 assert_eq!(
190 detect_format_from_filename("noextension"),
191 ObjectFormatCode::Undefined
192 );
193 }
194}