|
| 1 | +use emmylua_code_analysis::{FileId, LuaSemanticDeclId}; |
| 2 | +use serde::{Deserialize, Serialize}; |
| 3 | +use serde_json::Value; |
| 4 | + |
| 5 | +use super::completion_builder::CompletionBuilder; |
| 6 | + |
| 7 | +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] |
| 8 | +pub struct CompletionData { |
| 9 | + pub field_id: FileId, |
| 10 | + pub typ: CompletionDataType, |
| 11 | + /// Total count of function overloads |
| 12 | + pub function_overload_count: Option<usize>, |
| 13 | +} |
| 14 | + |
| 15 | +#[allow(unused)] |
| 16 | +impl CompletionData { |
| 17 | + pub fn from_property_owner_id( |
| 18 | + builder: &CompletionBuilder, |
| 19 | + id: LuaSemanticDeclId, |
| 20 | + function_overload_count: Option<usize>, |
| 21 | + ) -> Option<Value> { |
| 22 | + let data = Self { |
| 23 | + field_id: builder.semantic_model.get_file_id(), |
| 24 | + typ: CompletionDataType::PropertyOwnerId(id), |
| 25 | + function_overload_count, |
| 26 | + }; |
| 27 | + Some(serde_json::to_value(data).unwrap()) |
| 28 | + } |
| 29 | + |
| 30 | + pub fn from_overload( |
| 31 | + builder: &CompletionBuilder, |
| 32 | + id: LuaSemanticDeclId, |
| 33 | + index: usize, |
| 34 | + function_overload_count: Option<usize>, |
| 35 | + ) -> Option<Value> { |
| 36 | + let data = Self { |
| 37 | + field_id: builder.semantic_model.get_file_id(), |
| 38 | + typ: CompletionDataType::Overload((id, index)), |
| 39 | + function_overload_count, |
| 40 | + }; |
| 41 | + Some(serde_json::to_value(data).unwrap()) |
| 42 | + } |
| 43 | + |
| 44 | + pub fn from_module(builder: &CompletionBuilder, module: String) -> Option<Value> { |
| 45 | + let data = Self { |
| 46 | + field_id: builder.semantic_model.get_file_id(), |
| 47 | + typ: CompletionDataType::Module(module), |
| 48 | + function_overload_count: None, |
| 49 | + }; |
| 50 | + Some(serde_json::to_value(data).unwrap()) |
| 51 | + } |
| 52 | +} |
| 53 | + |
| 54 | +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] |
| 55 | +pub enum CompletionDataType { |
| 56 | + PropertyOwnerId(LuaSemanticDeclId), |
| 57 | + Module(String), |
| 58 | + Overload((LuaSemanticDeclId, usize)), |
| 59 | +} |
| 60 | + |
| 61 | +// // Custom serialization implementation |
| 62 | +// impl Serialize for CompletionData { |
| 63 | +// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
| 64 | +// where |
| 65 | +// S: Serializer, |
| 66 | +// { |
| 67 | +// // Compact format: "field_id|type_flag:type_data|overload_count" |
| 68 | +// // type_flag: P=PropertyOwnerId, M=Module, O=Overload |
| 69 | +// let type_part = match &self.typ { |
| 70 | +// CompletionDataType::PropertyOwnerId(id) => { |
| 71 | +// format!("P:{}", serde_json::to_string(id).map_err(serde::ser::Error::custom)?) |
| 72 | +// }, |
| 73 | +// CompletionDataType::Module(module) => { |
| 74 | +// format!("M:{}", module) |
| 75 | +// }, |
| 76 | +// CompletionDataType::Overload((id, index)) => { |
| 77 | +// format!("O:{}#{}", |
| 78 | +// serde_json::to_string(id).map_err(serde::ser::Error::custom)?, |
| 79 | +// index |
| 80 | +// ) |
| 81 | +// }, |
| 82 | +// }; |
| 83 | + |
| 84 | +// let overload_part = match self.function_overload_count { |
| 85 | +// Some(count) => format!("|{}", count), |
| 86 | +// None => String::new(), |
| 87 | +// }; |
| 88 | + |
| 89 | +// let compact = format!("{}|{}{}", self.field_id.id, type_part, overload_part); |
| 90 | +// serializer.serialize_str(&compact) |
| 91 | +// } |
| 92 | +// } |
| 93 | + |
| 94 | +// impl<'de> Deserialize<'de> for CompletionData { |
| 95 | +// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
| 96 | +// where |
| 97 | +// D: Deserializer<'de>, |
| 98 | +// { |
| 99 | +// struct CompletionDataVisitor; |
| 100 | + |
| 101 | +// impl<'de> Visitor<'de> for CompletionDataVisitor { |
| 102 | +// type Value = CompletionData; |
| 103 | + |
| 104 | +// fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
| 105 | +// formatter.write_str("a string with format 'field_id|type_flag:type_data|overload_count'") |
| 106 | +// } |
| 107 | + |
| 108 | +// fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> |
| 109 | +// where |
| 110 | +// E: de::Error, |
| 111 | +// { |
| 112 | +// let parts: Vec<&str> = value.split('|').collect(); |
| 113 | +// if parts.len() < 2 || parts.len() > 3 { |
| 114 | +// return Err(E::custom("expected format 'field_id|type_flag:type_data|overload_count'")); |
| 115 | +// } |
| 116 | + |
| 117 | +// // Parse field_id |
| 118 | +// let field_id = FileId::new( |
| 119 | +// parts[0] |
| 120 | +// .parse() |
| 121 | +// .map_err(|e| E::custom(format!("invalid field_id: {}", e)))? |
| 122 | +// ); |
| 123 | + |
| 124 | +// // Parse type |
| 125 | +// let type_part = parts[1]; |
| 126 | +// let typ = if let Some(colon_pos) = type_part.find(':') { |
| 127 | +// let type_flag = &type_part[..colon_pos]; |
| 128 | +// let type_data = &type_part[colon_pos + 1..]; |
| 129 | + |
| 130 | +// match type_flag { |
| 131 | +// "P" => { |
| 132 | +// let id: LuaSemanticDeclId = serde_json::from_str(type_data) |
| 133 | +// .map_err(|e| E::custom(format!("invalid PropertyOwnerId: {}", e)))?; |
| 134 | +// CompletionDataType::PropertyOwnerId(id) |
| 135 | +// }, |
| 136 | +// "M" => { |
| 137 | +// CompletionDataType::Module(type_data.to_string()) |
| 138 | +// }, |
| 139 | +// "O" => { |
| 140 | +// if let Some(hash_pos) = type_data.find('#') { |
| 141 | +// let id_part = &type_data[..hash_pos]; |
| 142 | +// let index_part = &type_data[hash_pos + 1..]; |
| 143 | + |
| 144 | +// let id: LuaSemanticDeclId = serde_json::from_str(id_part) |
| 145 | +// .map_err(|e| E::custom(format!("invalid Overload id: {}", e)))?; |
| 146 | +// let index: usize = index_part |
| 147 | +// .parse() |
| 148 | +// .map_err(|e| E::custom(format!("invalid Overload index: {}", e)))?; |
| 149 | + |
| 150 | +// CompletionDataType::Overload((id, index)) |
| 151 | +// } else { |
| 152 | +// return Err(E::custom("expected '#' separator in Overload type")); |
| 153 | +// } |
| 154 | +// }, |
| 155 | +// _ => { |
| 156 | +// return Err(E::custom(format!("unknown type flag: {}", type_flag))); |
| 157 | +// } |
| 158 | +// } |
| 159 | +// } else { |
| 160 | +// return Err(E::custom("expected ':' separator in type part")); |
| 161 | +// }; |
| 162 | + |
| 163 | +// // Parse function_overload_count |
| 164 | +// let function_overload_count = if parts.len() == 3 { |
| 165 | +// if parts[2].is_empty() { |
| 166 | +// None |
| 167 | +// } else { |
| 168 | +// Some( |
| 169 | +// parts[2] |
| 170 | +// .parse() |
| 171 | +// .map_err(|e| E::custom(format!("invalid overload count: {}", e)))? |
| 172 | +// ) |
| 173 | +// } |
| 174 | +// } else { |
| 175 | +// None |
| 176 | +// }; |
| 177 | + |
| 178 | +// Ok(CompletionData { |
| 179 | +// field_id, |
| 180 | +// typ, |
| 181 | +// function_overload_count, |
| 182 | +// }) |
| 183 | +// } |
| 184 | +// } |
| 185 | + |
| 186 | +// deserializer.deserialize_str(CompletionDataVisitor) |
| 187 | +// } |
| 188 | +// } |
| 189 | + |
| 190 | +// #[cfg(test)] |
| 191 | +// mod tests { |
| 192 | +// use emmylua_code_analysis::{FileId, LuaSemanticDeclId, LuaTypeDeclId}; |
| 193 | + |
| 194 | +// use super::{CompletionData, CompletionDataType}; |
| 195 | + |
| 196 | +// #[test] |
| 197 | +// fn test_compact_serialization() { |
| 198 | +// let type_id = LuaTypeDeclId::new("hello world"); |
| 199 | +// let data = CompletionData { |
| 200 | +// field_id: FileId::new(1), |
| 201 | +// typ: CompletionDataType::PropertyOwnerId(LuaSemanticDeclId::TypeDecl(type_id)), |
| 202 | +// function_overload_count: Some(3), |
| 203 | +// }; |
| 204 | + |
| 205 | +// // Test serialization |
| 206 | +// let json = serde_json::to_string(&data).unwrap(); |
| 207 | +// println!("Compact serialized: {}", json); |
| 208 | + |
| 209 | +// // Test deserialization |
| 210 | +// let deserialized: CompletionData = serde_json::from_str(&json).unwrap(); |
| 211 | +// assert_eq!(data, deserialized); |
| 212 | + |
| 213 | +// // Verify the compactness of serialization format |
| 214 | +// assert!(json.len() < 200); // Should be more compact than default JSON serialization |
| 215 | +// } |
| 216 | + |
| 217 | +// #[test] |
| 218 | +// fn test_module_serialization() { |
| 219 | +// let data = CompletionData { |
| 220 | +// field_id: FileId::new(42), |
| 221 | +// typ: CompletionDataType::Module("socket.core".to_string()), |
| 222 | +// function_overload_count: None, |
| 223 | +// }; |
| 224 | + |
| 225 | +// let json = serde_json::to_string(&data).unwrap(); |
| 226 | +// println!("Module serialized: {}", json); |
| 227 | + |
| 228 | +// let deserialized: CompletionData = serde_json::from_str(&json).unwrap(); |
| 229 | +// assert_eq!(data, deserialized); |
| 230 | +// } |
| 231 | + |
| 232 | +// #[test] |
| 233 | +// fn test_overload_serialization() { |
| 234 | +// let type_id = LuaTypeDeclId::new("test_function"); |
| 235 | +// let data = CompletionData { |
| 236 | +// field_id: FileId::new(10), |
| 237 | +// typ: CompletionDataType::Overload((LuaSemanticDeclId::TypeDecl(type_id), 2)), |
| 238 | +// function_overload_count: Some(5), |
| 239 | +// }; |
| 240 | + |
| 241 | +// let json = serde_json::to_string(&data).unwrap(); |
| 242 | +// println!("Overload serialized: {}", json); |
| 243 | + |
| 244 | +// let deserialized: CompletionData = serde_json::from_str(&json).unwrap(); |
| 245 | +// assert_eq!(data, deserialized); |
| 246 | +// } |
| 247 | + |
| 248 | +// #[test] |
| 249 | +// fn test_size_comparison() { |
| 250 | +// let type_id = LuaTypeDeclId::new("comparison_test"); |
| 251 | +// let data = CompletionData { |
| 252 | +// field_id: FileId::new(999), |
| 253 | +// typ: CompletionDataType::PropertyOwnerId(LuaSemanticDeclId::TypeDecl(type_id.clone())), |
| 254 | +// function_overload_count: Some(10), |
| 255 | +// }; |
| 256 | + |
| 257 | +// // Our compact serialization |
| 258 | +// let compact_json = serde_json::to_string(&data).unwrap(); |
| 259 | + |
| 260 | +// // Create a struct using default serialization to compare sizes |
| 261 | +// #[derive(serde::Serialize)] |
| 262 | +// struct DefaultSerialized { |
| 263 | +// field_id: u32, |
| 264 | +// typ: CompletionDataType, |
| 265 | +// function_overload_count: Option<usize>, |
| 266 | +// } |
| 267 | + |
| 268 | +// let default_data = DefaultSerialized { |
| 269 | +// field_id: data.field_id.id, |
| 270 | +// typ: data.typ.clone(), |
| 271 | +// function_overload_count: data.function_overload_count, |
| 272 | +// }; |
| 273 | + |
| 274 | +// let default_json = serde_json::to_string(&default_data).unwrap(); |
| 275 | + |
| 276 | +// println!("Compact size: {} bytes", compact_json.len()); |
| 277 | +// println!("Default size: {} bytes", default_json.len()); |
| 278 | + |
| 279 | +// // Compact serialization should be smaller |
| 280 | +// assert!(compact_json.len() <= default_json.len()); |
| 281 | +// } |
| 282 | +// } |
0 commit comments