diff options
Diffstat (limited to 'filamento/src/caps.rs')
-rw-r--r-- | filamento/src/caps.rs | 141 |
1 files changed, 92 insertions, 49 deletions
diff --git a/filamento/src/caps.rs b/filamento/src/caps.rs index 819e669..e0587ff 100644 --- a/filamento/src/caps.rs +++ b/filamento/src/caps.rs @@ -5,7 +5,8 @@ use sha1::Sha1; use sha2::{Digest, Sha256}; use sha3::Sha3_256; use stanza::{ - xep_0030::info, + xep_0004, + xep_0030::{self, info}, xep_0115::{self, C}, xep_0300::{self, Algo, Hash}, xep_0390, @@ -43,7 +44,11 @@ pub fn client_info() -> Info { ], // "http://jabber.org/protocol/nick".to_string(), identities: vec![Identity { - name: Some("filamento 0.1.0".to_string()), + name: Some(format!( + "{pkg} {version}", + pkg = env!("CARGO_PKG_NAME"), + version = env!("CARGO_PKG_VERSION"), + )), category: Category::Client(identity::Client::PC), }], } @@ -53,17 +58,26 @@ pub fn caps(node: String, query: info::Query) -> Result<xep_0115::C, CapsEncodeE let mut string = String::new(); // identities string - let mut identities = Vec::new(); + let mut identities = Vec::with_capacity(query.identities.len()); for identity in query.identities { - let mut string = String::new(); - string.push_str(&identity.category); + let (category, r#type, lang, name) = ( + identity.category, + identity.r#type, + identity.lang.unwrap_or_default(), + identity.name.unwrap_or_default(), + ); + + let mut string = + String::with_capacity(category.len() + r#type.len() + lang.len() + name.len() + 4); + string.push_str(&category); string.push('/'); - string.push_str(&identity.r#type); + string.push_str(&r#type); string.push('/'); - string.push_str(&identity.lang.unwrap_or_default()); + string.push_str(&lang); string.push('/'); - string.push_str(&identity.name.unwrap_or_default()); + string.push_str(&name); string.push('<'); + identities.push(string); } identities.sort(); @@ -71,11 +85,12 @@ pub fn caps(node: String, query: info::Query) -> Result<xep_0115::C, CapsEncodeE string.push_str(&identities_string); // features string - let mut features = Vec::new(); - for feature in query.features { - let mut string = String::new(); - string.push_str(&feature.var); + let mut features = Vec::with_capacity(query.features.len()); + for xep_0030::info::Feature { var, .. } in query.features { + let mut string = String::with_capacity(var.len() + 1); + string.push_str(&var); string.push('<'); + features.push(string); } features.sort(); @@ -83,45 +98,53 @@ pub fn caps(node: String, query: info::Query) -> Result<xep_0115::C, CapsEncodeE string.push_str(&features_string); // extensions string - let mut extensions = Vec::new(); + let mut extensions = Vec::with_capacity(query.extensions.len()); for extension in query.extensions { - let mut string = String::new(); let form_type = extension .fields .iter() .find(|field| field.var.as_deref() == Some("FORM_TYPE")) .ok_or(CapsEncodeError::InvalidDataForm)? .values - .clone() - .into_iter() - .map(|value| value.0) - .collect::<Vec<String>>() + .iter() + .map(|value| value.0.as_str()) + .collect::<Vec<&str>>() .concat(); - string.push_str(&form_type); - string.push('<'); - let mut fields = Vec::new(); + + let mut fields = Vec::with_capacity(extension.fields.len()); for field in extension.fields { if field.var.as_deref() == Some("FORM_TYPE") { continue; } - let mut string = String::new(); - string.push_str(&field.var.unwrap_or_default()); - string.push('<'); - let mut values = Vec::new(); - for value in field.values { - let mut string = String::new(); - string.push_str(&value.0); + + let var = field.var.unwrap_or_default(); + + let mut values = Vec::with_capacity(field.values.len()); + for xep_0004::Value(value) in field.values { + let mut string = String::with_capacity(value.len() + 1); + string.push_str(&value); string.push('<'); + values.push(string); } values.sort(); let values_string = values.concat(); + + let mut string = String::with_capacity(var.len() + values_string.len() + 1); + string.push_str(&var); + string.push('<'); string.push_str(&values_string); + fields.push(string); } fields.sort(); let fields_string = fields.concat(); + + let mut string = String::with_capacity(form_type.len() + fields_string.len() + 1); + string.push_str(&form_type); + string.push('<'); string.push_str(&fields_string); + extensions.push(string); } extensions.sort(); @@ -149,11 +172,12 @@ pub fn encode_caps2(query: info::Query) -> String { let mut string = String::new(); // features string - let mut features = Vec::new(); - for feature in query.features { - let mut string = String::new(); - string.push_str(&feature.var); + let mut features = Vec::with_capacity(query.features.len()); + for xep_0030::info::Feature { var, .. } in query.features { + let mut string = String::with_capacity(var.len() + 1); + string.push_str(&var); string.push('\x1f'); + features.push(string); } features.sort(); @@ -162,18 +186,27 @@ pub fn encode_caps2(query: info::Query) -> String { string.push('\x1c'); // identities string - let mut identities = Vec::new(); + let mut identities = Vec::with_capacity(query.identities.len()); for identity in query.identities { - let mut string = String::new(); - string.push_str(&identity.category); + let (category, r#type, lang, name) = ( + identity.category, + identity.r#type, + identity.lang.unwrap_or_default(), + identity.name.unwrap_or_default(), + ); + + let mut string = + String::with_capacity(category.len() + r#type.len() + lang.len() + name.len() + 5); + string.push_str(&category); string.push('\x1f'); - string.push_str(&identity.r#type); + string.push_str(&r#type); string.push('\x1f'); - string.push_str(&identity.lang.unwrap_or_default()); + string.push_str(&lang); string.push('\x1f'); - string.push_str(&identity.name.unwrap_or_default()); + string.push_str(&name); string.push('\x1f'); string.push('\x1e'); + identities.push(string); } identities.sort(); @@ -182,37 +215,45 @@ pub fn encode_caps2(query: info::Query) -> String { string.push('\x1c'); // extensions string - let mut extensions = Vec::new(); + let mut extensions = Vec::with_capacity(query.extensions.len()); for extension in query.extensions { - let mut string = String::new(); - let mut fields = Vec::new(); + let mut fields = Vec::with_capacity(extension.fields.len()); for field in extension.fields { - let mut string = String::new(); - string.push_str(&field.var.unwrap_or_default()); - string.push('\x1f'); - let mut values = Vec::new(); - for value in field.values { - let mut string = String::new(); - string.push_str(&value.0); + let var = field.var.unwrap_or_default(); + + let mut values = Vec::with_capacity(field.values.len()); + for xep_0004::Value(value) in field.values { + let mut string = String::with_capacity(value.len() + 1); + string.push_str(&value); string.push('\x1f'); + values.push(string); } values.sort(); let values_string = values.concat(); + + let mut string = String::with_capacity(var.len() + values_string.len() + 2); + string.push_str(&var); + string.push('\x1f'); string.push_str(&values_string); string.push('\x1e'); + fields.push(string); } fields.sort(); let fields_string = fields.concat(); + + let mut string = String::with_capacity(fields_string.len() + 1); string.push_str(&fields_string); string.push('\x1d'); + extensions.push(string); } extensions.sort(); let extensions_string = extensions.concat(); string.push_str(&extensions_string); string.push('\x1c'); + string } @@ -336,7 +377,7 @@ pub fn node_to_hash(node: String) -> Result<Hash, HashNodeConversionError> { #[cfg(test)] mod tests { - use peanuts::{Writer, element::IntoElement}; + use peanuts::Writer; use stanza::{ xep_0004::{Field, FieldType, Value, X, XType}, xep_0030::info::{Feature, Identity}, @@ -344,6 +385,7 @@ mod tests { use super::*; + #[cfg(not(target_arch = "wasm32"))] #[tokio::test] async fn test_caps() { tracing_subscriber::fmt().init(); @@ -448,6 +490,7 @@ mod tests { writer.write(&test_caps).await.unwrap(); } + #[cfg(not(target_arch = "wasm32"))] #[tokio::test] pub async fn test_gen_client_caps() { let stdout = tokio::io::stdout(); |