You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
146 lines
3.2 KiB
146 lines
3.2 KiB
use super::errors::CodecError; |
|
use serde::Serialize; |
|
use std::num::ParseIntError; |
|
use std::ops::Deref; |
|
use std::{collections::HashMap, u64}; |
|
|
|
/// A number encoded as a sequence of words |
|
#[derive(Debug, Clone, Serialize)] |
|
pub struct EncodedPart { |
|
pub value: u64, |
|
pub words: Vec<String>, |
|
} |
|
|
|
/// A way (variant) to split input number |
|
pub type EncodedSplit = Vec<EncodedPart>; |
|
|
|
/// A number encoded as words, split in multiple ways |
|
#[derive(Debug, Clone, Serialize)] |
|
pub struct EncodedValue(Vec<EncodedSplit>); |
|
|
|
impl EncodedValue { |
|
pub fn new(data: Vec<EncodedSplit>) -> Self { |
|
EncodedValue(data) |
|
} |
|
} |
|
|
|
impl Deref for EncodedValue { |
|
type Target = Vec<EncodedSplit>; |
|
|
|
fn deref(&self) -> &Self::Target { |
|
&self.0 |
|
} |
|
} |
|
|
|
/// The number value can be encoded as many word sets, |
|
/// but decoded as one number. For partial values |
|
/// and dictionary words (reasonable length), we can use |
|
/// u64 (20-digit number), but the whole input text can |
|
/// be longer than 20 digits, so we operate on String (<= 255). |
|
#[derive(Debug, Clone, PartialEq, Eq)] |
|
pub struct DecodedValue(String); |
|
|
|
impl DecodedValue { |
|
pub fn new(value: String) -> Result<Self, CodecError> { |
|
if value.len() > u8::MAX as usize { |
|
Err(CodecError::TextTooLong(value.len())) |
|
} else { |
|
Ok(Self(value)) |
|
} |
|
} |
|
|
|
pub fn as_str(&self) -> &str { |
|
&self.0 |
|
} |
|
|
|
pub fn parse(&self) -> Result<u64, ParseIntError> { |
|
self.0.parse() |
|
} |
|
|
|
pub fn len(&self) -> usize { |
|
self.0.len() |
|
} |
|
|
|
pub fn is_empty(&self) -> bool { |
|
self.0.is_empty() |
|
} |
|
|
|
pub fn value_len(&self) -> Result<DecodedLength, CodecError> { |
|
if self.len() == 0 { |
|
return Err(CodecError::EmptyValue); |
|
} |
|
DecodedLength::try_from(self.len()) |
|
} |
|
} |
|
|
|
impl PartialEq<&str> for DecodedValue { |
|
fn eq(&self, other: &&str) -> bool { |
|
&self.0 == *other |
|
} |
|
} |
|
|
|
impl PartialEq<DecodedValue> for &str { |
|
fn eq(&self, other: &DecodedValue) -> bool { |
|
*self == &other.0 |
|
} |
|
} |
|
|
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] |
|
pub struct DecodedLength(u8); |
|
|
|
impl DecodedLength { |
|
pub const fn from(value: u8) -> Self { |
|
Self(value) |
|
} |
|
} |
|
|
|
impl TryFrom<usize> for DecodedLength { |
|
type Error = CodecError; |
|
fn try_from(value: usize) -> Result<Self, CodecError> { |
|
if value > u8::MAX as usize { |
|
Err(CodecError::ValueLimitExceeded(value)) |
|
} else { |
|
Ok(Self(value as u8)) |
|
} |
|
} |
|
} |
|
|
|
// --- Dictionary --- |
|
|
|
pub type DictEntryId = u64; |
|
|
|
#[derive(Debug, Clone, PartialEq)] |
|
pub struct DictEntry { |
|
pub id: Option<DictEntryId>, |
|
pub text: String, |
|
pub metadata: HashMap<String, String>, |
|
} |
|
|
|
impl DictEntry { |
|
pub fn new(id: Option<DictEntryId>, text: String) -> Self { |
|
DictEntry { |
|
id, |
|
text, |
|
metadata: HashMap::new(), |
|
} |
|
} |
|
} |
|
|
|
#[derive(Debug, Clone)] |
|
pub struct Dict { |
|
pub name: String, |
|
pub entries: HashMap<DictEntryId, DictEntry>, |
|
} |
|
|
|
impl Dict { |
|
pub fn new(name: String) -> Self { |
|
Dict { |
|
name, |
|
entries: HashMap::new(), |
|
} |
|
} |
|
|
|
pub fn add_entry(&mut self, entry: DictEntry) { |
|
self.entries.insert(entry.id.unwrap(), entry); |
|
} |
|
}
|
|
|