serde_gff/
label.rs

1//! Содержит реализацию структуры, описывающей название поля в GFF файле и реализацию типажей для
2//! конвертации других типов данных в метку и обратно
3
4use std::fmt;
5use std::result::Result;
6use std::str::{from_utf8, FromStr, Utf8Error};
7use crate::error::Error;
8
9/// Описание названия поля структуры GFF файла. GFF файл состоит из дерева структур, а каждая
10/// структура -- из полей с именем и значением. Имена полей представлены данной структурой
11#[derive(Clone, Copy, PartialEq, Eq, Hash)]
12pub struct Label([u8; 16]);
13
14impl Label {
15  /// Возвращает представление данной метки как текста, если он представлен в виде `UTF-8` строки
16  pub fn as_str(&self) -> Result<&str, Utf8Error> {
17    for i in 0..self.0.len() {
18      // Во внутреннем представлении данные метки продолжаются до первого нулевого символа,
19      // однако сам нулевой символ не храниться -- это просто заполнитель
20      if self.0[i] == 0 {
21        return from_utf8(&self.0[0..i])
22      }
23    }
24    return from_utf8(&self.0);
25  }
26
27  /// Пытается создать метку из указанного массива байт.
28  ///
29  /// # Ошибки
30  /// В случае, если длина среза равна или превышает 16 байт, возвращается ошибка
31  /// [`Error::TooLongLabel`](./error/enum.Error.html#variant.TooLongLabel)
32  pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
33    if bytes.len() > 16 {
34      return Err(Error::TooLongLabel(bytes.len()));
35    }
36
37    let mut storage: [u8; 16] = Default::default();
38    let range = 0..bytes.len();
39    storage[range.clone()].copy_from_slice(&bytes[range]);
40    Ok(storage.into())
41  }
42}
43
44impl fmt::Debug for Label {
45  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
46    if let Ok(value) = self.as_str() {
47      return write!(f, "Label({})", value);
48    }
49    write!(f, "Label(")?;
50    self.0.fmt(f)?;
51    return write!(f, ")");
52  }
53}
54
55impl fmt::Display for Label {
56  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57    let value = self.as_str().map_err(|_| fmt::Error)?;
58    write!(f, "{}", value)
59  }
60}
61
62impl From<[u8; 16]> for Label {
63  fn from(arr: [u8; 16]) -> Self { Label(arr) }
64}
65
66impl AsRef<[u8]> for Label {
67  fn as_ref(&self) -> &[u8] { &self.0 }
68}
69
70impl FromStr for Label {
71  type Err = Error;
72
73  #[inline]
74  fn from_str(value: &str) -> Result<Self, Error> {
75    Self::from_bytes(value.as_bytes())
76  }
77}
78
79#[cfg(test)]
80mod tests {
81  use super::Label;
82
83  #[test]
84  fn label_constructs_from_str() {
85    assert_eq!(Label::from(*b"short\0\0\0\0\0\0\0\0\0\0\0"), "short".parse().unwrap());
86    assert_eq!(Label::from(*b"exact_16_chars_\0"), "exact_16_chars_".parse().unwrap());
87    assert!("more_then_16_char".parse::<Label>().is_err());
88  }
89}