Mountain/ApplicationState/DTO/
WorkspaceFolderStateDTO.rs1use serde::{Deserialize, Serialize};
13use url::Url;
14use CommonLibrary::Utility::Serialization::URLSerializationHelper;
15
16const MAX_FOLDER_NAME_LENGTH:usize = 256;
18
19const MAX_WORKSPACE_FOLDERS:usize = 100;
21
22#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
25#[serde(rename_all = "camelCase")]
26pub struct WorkspaceFolderStateDTO {
27 #[serde(rename = "uri", with = "URLSerializationHelper")]
29 pub URI:Url,
30
31 #[serde(skip_serializing_if = "String::is_empty")]
33 pub Name:String,
34
35 pub Index:usize,
37}
38
39impl WorkspaceFolderStateDTO {
40 pub fn New(URI:Url, Name:String, Index:usize) -> Result<Self, String> {
50 if URI.as_str().is_empty() {
52 return Err("URI cannot be empty".to_string());
53 }
54
55 if Name.len() > MAX_FOLDER_NAME_LENGTH {
57 return Err(format!(
58 "Folder name exceeds maximum length of {} bytes",
59 MAX_FOLDER_NAME_LENGTH
60 ));
61 }
62
63 if Index >= MAX_WORKSPACE_FOLDERS {
65 return Err(format!(
66 "Folder index {} exceeds maximum workspace folders count of {}",
67 Index, MAX_WORKSPACE_FOLDERS
68 ));
69 }
70
71 Ok(Self { URI, Name, Index })
72 }
73
74 pub fn UpdateName(&mut self, Name:String) -> Result<(), String> {
82 if Name.len() > MAX_FOLDER_NAME_LENGTH {
83 return Err(format!(
84 "Folder name exceeds maximum length of {} bytes",
85 MAX_FOLDER_NAME_LENGTH
86 ));
87 }
88
89 self.Name = Name;
90
91 Ok(())
92 }
93
94 pub fn GetDisplayName(&self) -> String {
97 if !self.Name.is_empty() {
98 self.Name.clone()
99 } else {
100 self.URI
102 .path_segments()
103 .and_then(|Segments| Segments.last())
104 .unwrap_or("Untitled")
105 .to_string()
106 }
107 }
108
109 pub fn IsRoot(&self) -> bool { self.Index == 0 }
111
112 pub fn FromPath(FolderPath:&str, Index:usize) -> Result<Self, String> {
121 let URI = Url::parse(FolderPath).map_err(|Error| format!("Invalid folder path: {}", Error))?;
122
123 let IsDirectory =
126 URI.path().ends_with('/') || (URI.scheme() == "file" && URI.to_file_path().map_or(false, |p| p.is_dir()));
127
128 if !IsDirectory {
129 return Err("URI does not represent a directory".to_string());
130 }
131
132 let Name = Self::ExtractFolderName(&URI);
133
134 Self::New(URI, Name, Index)
135 }
136
137 fn ExtractFolderName(URI:&Url) -> String {
139 URI.path_segments()
140 .and_then(|Segments| Segments.last())
141 .map(String::from)
142 .unwrap_or_else(|| "Untitled".to_string())
143 }
144}
145
146#[cfg(test)]
147mod tests {
148
149 use super::*;
150
151 #[test]
152 fn test_creation_success() {
153 let URI = Url::parse("file:///workspace/project").unwrap();
154
155 let dto = WorkspaceFolderStateDTO::New(URI.clone(), "project".to_string(), 0);
156
157 assert!(dto.is_ok());
158
159 assert_eq!(dto.unwrap().Name, "project");
160 }
161
162 #[test]
163 fn test_invalid_name_length() {
164 let URI = Url::parse("file:///workspace/project").unwrap();
165
166 let LongName = "a".repeat(257);
167
168 let dto = WorkspaceFolderStateDTO::New(URI, LongName, 0);
169
170 assert!(dto.is_err());
171 }
172
173 #[test]
174 fn test_invalid_index() {
175 let URI = Url::parse("file:///workspace/project").unwrap();
176
177 let dto = WorkspaceFolderStateDTO::New(URI, "project".to_string(), 100);
178
179 assert!(dto.is_err());
180 }
181}