use std::{
fmt,
io::{Read, Write},
};
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use crate::types::{
encoding::{
process_decode_io_result, process_encode_io_result, write_i32, BinaryEncoder,
DecodingOptions, EncodingResult,
},
status_codes::StatusCode,
};
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub struct UAString {
value: Option<String>,
}
impl fmt::Display for UAString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(ref value) = self.value {
write!(f, "{}", value)
} else {
write!(f, "[null]")
}
}
}
impl Serialize for UAString {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if let Some(s) = self.value.as_ref() {
serializer.serialize_str(&s)
} else {
serializer.serialize_none()
}
}
}
struct UAStringVisitor;
impl<'de> serde::de::Visitor<'de> for UAStringVisitor {
type Value = UAString;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a string value or null")
}
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Self::Value::null())
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_str(self)
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Self::Value::from(v))
}
}
impl<'de> Deserialize<'de> for UAString {
fn deserialize<D>(deserializer: D) -> Result<UAString, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_option(UAStringVisitor)
}
}
impl BinaryEncoder<UAString> for UAString {
fn byte_len(&self) -> usize {
4 + if self.value.is_none() {
0
} else {
self.value.as_ref().unwrap().len()
}
}
fn encode<S: Write>(&self, stream: &mut S) -> EncodingResult<usize> {
if self.value.is_none() {
write_i32(stream, -1)
} else {
let value = self.value.as_ref().unwrap();
let mut size: usize = 0;
size += write_i32(stream, value.len() as i32)?;
let buf = value.as_bytes();
size += process_encode_io_result(stream.write(buf))?;
assert_eq!(size, self.byte_len());
Ok(size)
}
}
fn decode<S: Read>(stream: &mut S, decoding_options: &DecodingOptions) -> EncodingResult<Self> {
let len = i32::decode(stream, decoding_options)?;
if len == -1 {
Ok(UAString::null())
} else if len < -1 {
error!("String buf length is a negative number {}", len);
Err(StatusCode::BadDecodingError)
} else if len as usize > decoding_options.max_string_length {
error!(
"String buf length {} exceeds decoding limit {}",
len, decoding_options.max_string_length
);
Err(StatusCode::BadDecodingError)
} else {
let mut buf = vec![0u8; len as usize];
process_decode_io_result(stream.read_exact(&mut buf))?;
let value = String::from_utf8(buf).map_err(|err| {
trace!("Decoded string was not valid UTF-8 - {}", err.to_string());
StatusCode::BadDecodingError
})?;
Ok(UAString::from(value))
}
}
}
impl From<UAString> for String {
fn from(value: UAString) -> Self {
value.as_ref().to_string()
}
}
impl AsRef<str> for UAString {
fn as_ref(&self) -> &str {
if self.is_null() {
""
} else {
self.value.as_ref().unwrap()
}
}
}
impl<'a> From<&'a str> for UAString {
fn from(value: &'a str) -> Self {
Self::from(value.to_string())
}
}
impl From<&String> for UAString {
fn from(value: &String) -> Self {
UAString {
value: Some(value.clone()),
}
}
}
impl From<String> for UAString {
fn from(value: String) -> Self {
UAString { value: Some(value) }
}
}
impl Default for UAString {
fn default() -> Self {
UAString::null()
}
}
impl<'a, 'b> PartialEq<str> for UAString {
fn eq(&self, other: &str) -> bool {
match self.value {
None => false,
Some(ref v) => v.eq(other),
}
}
}
impl UAString {
pub fn value(&self) -> &Option<String> {
&self.value
}
pub fn set_value(&mut self, value: Option<String>) {
self.value = value;
}
pub fn is_empty(&self) -> bool {
if self.value.is_none() {
true
} else {
self.value.as_ref().unwrap().is_empty()
}
}
pub fn len(&self) -> isize {
if self.value.is_none() {
-1
} else {
self.value.as_ref().unwrap().len() as isize
}
}
pub fn null() -> UAString {
UAString { value: None }
}
pub fn is_null(&self) -> bool {
self.value.is_none()
}
pub fn substring(&self, min: usize, max: usize) -> Result<UAString, ()> {
if let Some(ref v) = self.value() {
if min >= v.len() {
Err(())
} else {
let max = if max >= v.len() { v.len() - 1 } else { max };
Ok(UAString::from(&v[min..=max]))
}
} else {
Err(())
}
}
}
#[test]
fn string_null() {
let s = UAString::null();
assert!(s.is_null());
assert!(s.is_empty());
assert_eq!(s.len(), -1);
}
#[test]
fn string_empty() {
let s = UAString::from("");
assert!(!s.is_null());
assert!(s.is_empty());
assert_eq!(s.len(), 0);
}
#[test]
fn string_value() {
let v = "Mary had a little lamb";
let s = UAString::from(v);
assert!(!s.is_null());
assert!(!s.is_empty());
assert_eq!(s.as_ref(), v);
}
#[test]
fn string_eq() {
let s = UAString::null();
assert!(!s.eq(""));
let s = UAString::from("");
assert!(s.eq(""));
let s = UAString::from("Sunshine");
assert!(s.ne("Moonshine"));
assert!(s.eq("Sunshine"));
assert!(!s.eq("Sunshine "));
}
#[test]
fn string_substring() {
let a = "Mary had a little lamb";
let v = UAString::from(a);
let v2 = v.substring(0, 4).unwrap();
let a2 = v2.as_ref();
assert_eq!(a2, "Mary ");
let v2 = v.substring(2, 2).unwrap();
let a2 = v2.as_ref();
assert_eq!(a2, "r");
let v2 = v.substring(0, 2000).unwrap();
assert_eq!(v, v2);
assert_eq!(v2.as_ref(), a);
assert!(v.substring(22, 10000).is_err());
assert!(UAString::null().substring(0, 0).is_err());
}
pub type XmlElement = UAString;