use std::str::FromStr;
use super::{
parameter_name::{FieldParameterName, InvalidEncodedFieldParameterName},
parameter_value::{FieldParameterValue, InvalidEncodedFieldParameterValue},
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FieldParameter {
pub name: FieldParameterName,
pub value: FieldParameterValue,
}
#[derive(Debug, Clone, thiserror::Error, PartialEq, Eq)]
pub enum InvalidEncodedFieldParameter {
#[error("Invalid parameter encoding")]
InvalidParameterEncoding,
#[error("Invalid parameter name")]
InvalidParameterName(#[from] InvalidEncodedFieldParameterName),
#[error("Invalid parameter value")]
InvalidParameterValue(#[from] InvalidEncodedFieldParameterValue),
}
impl FieldParameter {
pub fn decode(
value: &str,
allow_implicit_param_value: bool,
) -> Result<Self, InvalidEncodedFieldParameter> {
let mut value_split = value.split_once('=');
if value_split.is_none() && allow_implicit_param_value {
value_split = Some((value, "\"\""));
}
let (k, v) = value_split.ok_or(InvalidEncodedFieldParameter::InvalidParameterEncoding)?;
Ok(Self {
name: FieldParameterName::from_str(k.trim())?,
value: FieldParameterValue::decode(v.trim())?,
})
}
#[inline]
pub fn push_encoded_str(&self, buffer: &mut String) {
self.name.push_encoded_str(buffer);
buffer.push('=');
self.value.push_encoded_str(buffer);
}
#[inline]
pub fn str_encode(&self) -> String {
let mut encoded = String::new();
self.push_encoded_str(&mut encoded);
encoded
}
}
#[cfg(test)]
mod tests_decode {
use claims::{assert_err, assert_err_eq, assert_matches, assert_ok};
use rstest::*;
use super::*;
#[rstest]
#[case("abc")]
#[case("abc def")]
fn invalid_encoded_param_will_be_rejected(#[case] param_str: &str) {
assert_err_eq!(
FieldParameter::decode(param_str, false),
InvalidEncodedFieldParameter::InvalidParameterEncoding
);
}
#[rstest]
#[case("a/b = cd")]
#[case("a{b} = cd")]
#[case("a b = cd")]
#[case("रा = _")]
fn param_with_invalid_key_will_be_rejected(#[case] param_str: &str) {
assert_matches!(
claims::assert_err!(FieldParameter::decode(param_str, false)),
InvalidEncodedFieldParameter::InvalidParameterName(..)
);
}
#[rstest]
#[case("ab = c/d")]
#[case("ab = c{d}")]
#[case("ab = \"ab\\\"c\"")]
#[case("_ = रा")]
#[case("_ = \"रा\"")]
fn param_with_invalid_value_will_be_rejected(#[case] param_str: &str) {
assert_matches!(
assert_err!(FieldParameter::decode(param_str, false)),
InvalidEncodedFieldParameter::InvalidParameterValue(..)
);
}
fn assert_param_match(
param: &FieldParameter,
expected_key_str: &str,
expected_value_str: &str,
) {
assert_eq!(
param.name,
FieldParameterName::from_str(expected_key_str).unwrap()
);
assert_eq!(param.value.as_ref(), expected_value_str);
}
#[rstest]
#[case("a=b", "a", "b")]
#[case("a = b", "a", "b")]
#[case("abc=\"b\"", "abc", "b")]
#[case("KK=b", "kk", "b")]
#[case("a=b", "a", "b")]
#[case("a=\"b c d e\"", "a", "b c d e")]
#[case("a=b.png", "a", "b.png")]
fn valid_param_will_be_parsed_correctly(
#[case] param_str: &str,
#[case] expected_key_str: &str,
#[case] expected_value_str: &str,
) {
let param = assert_ok!(FieldParameter::decode(param_str, false));
assert_param_match(¶m, expected_key_str, expected_value_str);
}
#[rstest]
#[case("a", "a", "")]
#[case("a = b", "a", "b")]
#[case("abc=\"\"", "abc", "")]
#[case("KK", "kk", "")]
fn valid_implicit_param_will_be_parsed_correctly(
#[case] param_str: &str,
#[case] expected_key_str: &str,
#[case] expected_value_str: &str,
) {
let param = assert_ok!(FieldParameter::decode(param_str, true));
assert_param_match(¶m, expected_key_str, expected_value_str);
}
}