use bincode as bin;
#[cfg(any(feature = "embed_all", feature = "embed_en-us"))]
use crate::resources::ResourceId;
use std::error;
use std::fmt;
use std::fs::File;
use std::io;
use std::path::Path;
use std::result;
use hyphenation_commons::dictionary::{extended::Extended, Standard};
use hyphenation_commons::Language;
pub trait Load: Sized {
fn from_path<P>(lang : Language, path : P) -> Result<Self>
where P : AsRef<Path>
{
let file = File::open(path)?;
Self::from_reader(lang, &mut io::BufReader::new(file))
}
fn from_reader<R>(lang : Language, reader : &mut R) -> Result<Self>
where R : io::Read;
fn any_from_reader<R>(reader : &mut R) -> Result<Self>
where R : io::Read;
#[cfg(any(feature = "embed_all", feature = "embed_en-us"))]
fn from_embedded(lang : Language) -> Result<Self>;
}
macro_rules! impl_load {
($dict:ty, $suffix:expr) => {
impl Load for $dict {
fn from_reader<R>(lang : Language, reader : &mut R) -> Result<Self>
where R : io::Read
{
let dict : Self = bin::deserialize_from(reader)?;
let (found, expected) = (dict.language(), lang);
if found != expected {
Err(Error::LanguageMismatch { expected, found })
} else {
Ok(dict)
}
}
fn any_from_reader<R>(reader : &mut R) -> Result<Self>
where R : io::Read
{
let dict : Self = bin::deserialize_from(reader)?;
Ok(dict)
}
#[cfg(any(feature = "embed_all", feature = "embed_en-us"))]
fn from_embedded(lang : Language) -> Result<Self> {
let dict_bytes = retrieve_resource(lang.code(), $suffix)?;
let dict = bin::deserialize(dict_bytes)?;
Ok(dict)
}
}
};
}
impl_load! { Standard, "standard" }
impl_load! { Extended, "extended" }
#[cfg(any(feature = "embed_all", feature = "embed_en-us"))]
fn retrieve_resource<'a>(code : &str, suffix : &str) -> Result<&'a [u8]> {
let name = format!("{}.{}.bincode", code, suffix);
let res : Option<ResourceId> = ResourceId::from_name(&name);
match res {
Some(data) => Ok(data.load()),
None => Err(Error::Resource),
}
}
pub type Result<T> = result::Result<T, Error>;
#[derive(Debug)]
pub enum Error {
Deserialization(bin::Error),
IO(io::Error),
LanguageMismatch {
expected : Language,
found : Language,
},
Resource,
}
impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match *self {
Error::Deserialization(ref e) => Some(e),
Error::IO(ref e) => Some(e),
_ => None,
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::Deserialization(ref e) => e.fmt(f),
Error::IO(ref e) => e.fmt(f),
Error::LanguageMismatch { expected, found } => write!(
f,
"\
Language mismatch: attempted to load a dictionary for `{}`, but found
a dictionary for `{}` instead.",
expected, found
),
Error::Resource => f.write_str("the embedded dictionary could not be retrieved"),
}
}
}
impl From<io::Error> for Error {
fn from(err : io::Error) -> Error { Error::IO(err) }
}
impl From<bin::Error> for Error {
fn from(err : bin::Error) -> Error { Error::Deserialization(err) }
}