encodings.rs

 1//! Encoding and decoding utilities using the `encoding` crate.
 2use std::fmt::Debug;
 3
 4use anyhow::{Error, Result};
 5use encoding::Encoding;
 6use serde::{Deserialize, de::Visitor};
 7
 8/// A wrapper around `encoding::Encoding` to implement `Send` and `Sync`.
 9/// Since the reference is static, it is safe to send it across threads.
10pub struct EncodingWrapper(&'static dyn Encoding);
11
12impl Debug for EncodingWrapper {
13    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14        f.debug_tuple("EncodingWrapper")
15            .field(&self.0.name())
16            .finish()
17    }
18}
19
20pub struct EncodingWrapperVisitor;
21
22impl<'vi> Visitor<'vi> for EncodingWrapperVisitor {
23    type Value = EncodingWrapper;
24
25    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
26        formatter.write_str("a valid encoding name")
27    }
28
29    fn visit_str<E: serde::de::Error>(self, encoding: &str) -> Result<EncodingWrapper, E> {
30        Ok(EncodingWrapper(
31            encoding::label::encoding_from_whatwg_label(encoding)
32                .ok_or_else(|| serde::de::Error::custom("Invalid Encoding"))?,
33        ))
34    }
35
36    fn visit_string<E: serde::de::Error>(self, encoding: String) -> Result<EncodingWrapper, E> {
37        Ok(EncodingWrapper(
38            encoding::label::encoding_from_whatwg_label(&encoding)
39                .ok_or_else(|| serde::de::Error::custom("Invalid Encoding"))?,
40        ))
41    }
42}
43
44impl<'de> Deserialize<'de> for EncodingWrapper {
45    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
46    where
47        D: serde::Deserializer<'de>,
48    {
49        deserializer.deserialize_str(EncodingWrapperVisitor)
50    }
51}
52
53impl PartialEq for EncodingWrapper {
54    fn eq(&self, other: &Self) -> bool {
55        self.0.name() == other.0.name()
56    }
57}
58
59unsafe impl Send for EncodingWrapper {}
60unsafe impl Sync for EncodingWrapper {}
61
62impl Clone for EncodingWrapper {
63    fn clone(&self) -> Self {
64        EncodingWrapper(self.0)
65    }
66}
67
68impl EncodingWrapper {
69    pub fn new(encoding: &'static dyn Encoding) -> EncodingWrapper {
70        EncodingWrapper(encoding)
71    }
72
73    pub async fn decode(&self, input: Vec<u8>) -> Result<String> {
74        match self.0.decode(&input, encoding::DecoderTrap::Replace) {
75            Ok(v) => Ok(v),
76            Err(e) => Err(Error::msg(e.to_string())),
77        }
78    }
79
80    pub async fn encode(&self, input: String) -> Result<Vec<u8>> {
81        match self.0.encode(&input, encoding::EncoderTrap::Replace) {
82            Ok(v) => Ok(v),
83            Err(e) => Err(Error::msg(e.to_string())),
84        }
85    }
86}
87
88/// Convert a byte vector from a specified encoding to a UTF-8 string.
89pub async fn to_utf8<'a>(input: Vec<u8>, encoding: EncodingWrapper) -> Result<String> {
90    Ok(encoding.decode(input).await?)
91}
92
93/// Convert a UTF-8 string to a byte vector in a specified encoding.
94pub async fn from_utf8<'a>(input: String, target: EncodingWrapper) -> Result<Vec<u8>> {
95    Ok(target.encode(input).await?)
96}