extern crate alloc;
use core::hash::Hash;
use alloc::collections::BTreeSet;
use alloc::rc::Rc;
use alloc::sync::Arc;
use beancount_types::Account;
use beancount_types::Directive;
use delegate::delegate;
use time::Date;
pub mod error;
pub mod runner;
pub mod utilities;
pub trait ImporterProtocol {
type Error;
fn account(&self, buffer: &[u8]) -> Result<Account, Self::Error>;
fn date(&self, _buffer: &[u8]) -> Option<Result<Date, Self::Error>> {
None
}
fn extract(&self, buffer: &[u8], existing: &[Directive])
-> Result<Vec<Directive>, Self::Error>;
fn filename(&self, _buffer: &[u8]) -> Option<Result<String, Self::Error>> {
None
}
fn identify(&self, buffer: &[u8]) -> Result<bool, Self::Error>;
fn name(&self) -> &'static str;
#[doc(hidden)]
fn typetag_deserialize(&self);
}
impl<I> ImporterProtocol for &I
where
I: ImporterProtocol + ?Sized,
{
type Error = I::Error;
delegate! {
to (*self) {
fn account(&self, buffer: &[u8]) -> Result<Account, Self::Error>;
fn date(&self, _buffer: &[u8]) -> Option<Result<Date, Self::Error>>;
fn extract(&self, buffer: &[u8], existing: &[Directive]) -> Result<Vec<Directive>, Self::Error>;
fn filename(&self, buffer: &[u8]) -> Option<Result<String, Self::Error>>;
fn identify(&self, buffer: &[u8]) -> Result<bool, Self::Error>;
fn name(&self) -> &'static str;
fn typetag_deserialize(&self);
}
}
}
impl<I> ImporterProtocol for Arc<I>
where
I: ImporterProtocol + ?Sized,
{
type Error = I::Error;
delegate! {
to (**self) {
fn account(&self, buffer: &[u8]) -> Result<Account, Self::Error>;
fn date(&self, _buffer: &[u8]) -> Option<Result<Date, Self::Error>>;
fn extract(&self, buffer: &[u8], existing: &[Directive]) -> Result<Vec<Directive>, Self::Error>;
fn filename(&self, buffer: &[u8]) -> Option<Result<String, Self::Error>>;
fn identify(&self, buffer: &[u8]) -> Result<bool, Self::Error>;
fn name(&self) -> &'static str;
fn typetag_deserialize(&self);
}
}
}
impl<I> ImporterProtocol for Box<I>
where
I: ImporterProtocol + ?Sized,
{
type Error = I::Error;
delegate! {
to (**self) {
fn account(&self, buffer: &[u8]) -> Result<Account, Self::Error>;
fn date(&self, _buffer: &[u8]) -> Option<Result<Date, Self::Error>>;
fn extract(&self, buffer: &[u8], existing: &[Directive]) -> Result<Vec<Directive>, Self::Error>;
fn filename(&self, buffer: &[u8]) -> Option<Result<String, Self::Error>>;
fn identify(&self, buffer: &[u8]) -> Result<bool, Self::Error>;
fn name(&self) -> &'static str;
fn typetag_deserialize(&self);
}
}
}
impl<I> ImporterProtocol for Rc<I>
where
I: ImporterProtocol + ?Sized,
{
type Error = I::Error;
delegate! {
to (**self) {
fn account(&self, buffer: &[u8]) -> Result<Account, Self::Error>;
fn date(&self, _buffer: &[u8]) -> Option<Result<Date, Self::Error>>;
fn extract(&self, buffer: &[u8], existing: &[Directive]) -> Result<Vec<Directive>, Self::Error>;
fn filename(&self, buffer: &[u8]) -> Option<Result<String, Self::Error>>;
fn identify(&self, buffer: &[u8]) -> Result<bool, Self::Error>;
fn name(&self) -> &'static str;
fn typetag_deserialize(&self);
}
}
}
#[derive(Debug)]
pub struct ImporterRegistry<E> {
importers: BTreeSet<NamedImporter<E>>,
}
impl<E> Default for ImporterRegistry<E> {
fn default() -> Self {
let importers = Default::default();
Self { importers }
}
}
impl<E> ImporterRegistry<E> {
pub fn register_importer<I>(&mut self, importer: I) -> &mut Self
where
I: ImporterProtocol<Error = E> + 'static,
{
let name = importer.name();
if !self.importers.insert(NamedImporter::new(importer)) {
tracing::warn!(importer = name, "importer has already been registered");
}
self
}
}
impl<E> ImporterRegistry<E> {
pub fn iter(&self) -> impl Iterator<Item = &dyn ImporterProtocol<Error = E>> {
self.importers.iter().map(|importer| &*importer.0)
}
}
struct NamedImporter<E>(Box<dyn ImporterProtocol<Error = E>>);
impl<E> NamedImporter<E> {
fn new<I>(importer: I) -> Self
where
I: ImporterProtocol<Error = E> + 'static,
{
Self(Box::new(importer))
}
}
impl<E> core::fmt::Debug for NamedImporter<E> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("NamedImporter")
.field(&self.0.name())
.finish()
}
}
impl<E> Eq for NamedImporter<E> {}
impl<E> From<Box<dyn ImporterProtocol<Error = E>>> for NamedImporter<E> {
fn from(value: Box<dyn ImporterProtocol<Error = E>>) -> Self {
Self(value)
}
}
impl<E> Hash for NamedImporter<E> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.0.name().hash(state);
}
}
impl<E> Ord for NamedImporter<E> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.name().cmp(other.0.name())
}
}
impl<E> PartialEq for NamedImporter<E> {
fn eq(&self, other: &Self) -> bool {
self.cmp(other).is_eq()
}
}
impl<E> PartialOrd for NamedImporter<E> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}