basic implementation for EmoteMapper

[?]
8LW8624xwrzheYNE1i3XKqUsNUezeTo6cRFa6qrKJout
Oct 10, 2021, 9:42 PM
BK53SCKOZP5KD4QHQJWL4SOA543MT7JM7DTFNXQBM2IZK4UMUFOAC

Dependencies

Change contents

  • replacement in src/lib.rs at line 1
    [2.47][2.48:135]()
    #[cfg(test)]
    mod tests {
    #[test]
    fn it_works() {
    assert_eq!(2 + 2, 4);
    [2.47]
    [2.135]
    use std::{
    collections::HashMap,
    convert::TryFrom,
    fmt::Display,
    fs::File,
    io::{Read, Write},
    path::Path,
    str::FromStr,
    };
    use csv::Trim;
    use serde::*;
    use serde_with::{serde_as, TryFromInto};
    use thiserror::Error;
    use EmoteMapperError::*;
    pub struct EmoteMapper {
    map: HashMap<String, CodePoint>,
    emote_width: usize,
    }
    impl Default for EmoteMapper {
    fn default() -> Self {
    Self {
    map: Default::default(),
    emote_width: 3,
    }
    }
    }
    impl EmoteMapper {
    pub fn emote_width(mut self, emote_width: usize) -> Self {
    self.emote_width = emote_width;
    self
    }
    pub fn to_char(&self, emote_name: &str) -> Option<char> {
    self.map.get(emote_name).copied().map(char::from)
    }
    pub fn to_string(&self, emote_name: &str) -> Option<String> {
    self.to_char(emote_name)
    .map(|c| format!("{}{}", c, " ".repeat(self.emote_width - 1)))
    }
    }
    /// Parsing
    impl EmoteMapper {
    pub fn from_reader(rdr: impl Read) -> Result<Self, EmoteMapperError> {
    let mut rdr = csv::ReaderBuilder::new()
    .has_headers(false)
    .trim(Trim::All)
    .from_reader(rdr);
    let map = rdr
    .deserialize::<Mapping>()
    .map(|r| {
    let r: Mapping = r.map_err(StringParsingError)?;
    Ok((r.name, r.code_point))
    })
    .collect::<Result<_, EmoteMapperError>>()?;
    Ok(EmoteMapper {
    map,
    ..EmoteMapper::default()
    })
    }
    pub fn from_path(p: &Path) -> Result<Self, EmoteMapperError> {
    Self::from_reader(File::open(p).map_err(IOError)?)
    }
    }
    impl FromStr for EmoteMapper {
    type Err = EmoteMapperError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
    Self::from_reader(s.as_bytes())
    }
    }
    /// Saving
    impl EmoteMapper {
    pub fn to_writer(self, wtr: impl Write) -> Result<(), EmoteMapperError> {
    let mut wtr = csv::WriterBuilder::new()
    .has_headers(false)
    .from_writer(wtr);
    for mapping in self.map.into_iter().map(Mapping::from) {
    wtr.serialize(mapping).unwrap();
    }
    wtr.flush().map_err(IOError)
    }
    pub fn to_path(self, p: &Path) -> Result<(), EmoteMapperError> {
    self.to_writer(File::open(p).map_err(IOError)?)
    }
    }
    impl From<EmoteMapper> for String {
    fn from(val: EmoteMapper) -> Self {
    let mut s = "".to_string();
    {
    val.to_writer(unsafe { s.as_mut_vec() })
    .expect("Writing to String should not fail");
    }
    s
    }
    }
    #[test]
    fn from_into_str() {
    let str = "testEmote,F4000\n";
    let em = EmoteMapper::from_str(str).unwrap();
    assert_eq!(em.map.get("testEmote").unwrap().0, '\u{F4000}');
    assert_eq!(String::from(em), str)
    }
    #[serde_as]
    #[derive(Debug, Deserialize, Serialize)]
    struct Mapping {
    name: String,
    #[serde_as(as = "TryFromInto<String>")]
    code_point: CodePoint,
    }
    impl From<(String, CodePoint)> for Mapping {
    fn from((name, code_point): (String, CodePoint)) -> Self {
    Mapping { name, code_point }
    }
    }
    #[derive(Error, Debug)]
    pub enum EmoteMapperError {
    #[error("codepoint is expected to be a hex number: `{0}`")]
    InvalidCodepoint(String),
    #[error("Parsing from string failed with:\n{0}")]
    StringParsingError(csv::Error),
    #[error("Failed due to IO-Error:\n{0}")]
    IOError(std::io::Error),
    }
    #[derive(Clone, Copy, Debug)]
    struct CodePoint(char);
    impl From<CodePoint> for char {
    fn from(cp: CodePoint) -> Self {
    cp.0
    }
    }
    impl Display for CodePoint {
    fn fmt(&self, f: &mut __private::Formatter<'_>) -> std::fmt::Result {
    char::from(*self).fmt(f)
    }
    }
    impl From<CodePoint> for String {
    fn from(val: CodePoint) -> Self {
    format!("{:X}", val.0 as u32)
    }
    }
    impl TryFrom<String> for CodePoint {
    type Error = EmoteMapperError;
    fn try_from(s: String) -> Result<Self, Self::Error> {
    Ok(CodePoint(
    char::from_u32(
    u32::from_str_radix(&s, 16).map_err(|_| InvalidCodepoint(s.to_string()))?,
    )
    .ok_or_else(|| InvalidCodepoint(s.to_string()))?,
    ))
  • edit in Cargo.toml at line 9
    [2.361]
    csv = "1.1.6"
    serde = { version = "1.0.130", features = ["derive"] }
    serde_with = { version = "1.10.0", features = ["hex"] }
    thiserror = "1.0.30"