aboutsummaryrefslogtreecommitdiffstats
path: root/filamento/src/caps.rs
diff options
context:
space:
mode:
Diffstat (limited to 'filamento/src/caps.rs')
-rw-r--r--filamento/src/caps.rs141
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();