2017-02-16 01:05:33 -06:00
use std ::collections ::BTreeMap ;
use std ::error ::Error ;
use std ::fmt ;
use toml ::Table ;
use modules ::Module ;
use modules ::discord ::DiscordModule ;
use modules ::lua ::LuaModule ;
use modules ::stdin ::StdinModule ;
use modules ::echo ::EchoModule ;
2017-02-16 02:00:38 -06:00
use modules ::random ::RandomModule ;
2017-02-19 04:49:06 -06:00
use modules ::pvn ::PvnModule ;
2017-02-22 23:40:30 -06:00
use modules ::echobox ::EchoboxModule ;
2017-02-26 17:17:22 -06:00
use modules ::autolink ::AutolinkModule ;
2017-02-16 01:05:33 -06:00
pub struct ModuleLoader {
2017-02-26 02:44:53 -06:00
types : BTreeMap < & 'static str , fn ( & Table , & Table ) -> Box < Module > >
2017-02-16 01:05:33 -06:00
}
impl ModuleLoader {
pub fn new ( ) -> ModuleLoader {
let mut types = BTreeMap ::new ( ) ;
2017-02-26 02:44:53 -06:00
types . insert ( " discord " , DiscordModule ::new as fn ( & Table , & Table ) -> Box < Module > ) ;
types . insert ( " lua " , LuaModule ::new as fn ( & Table , & Table ) -> Box < Module > ) ;
types . insert ( " stdin " , StdinModule ::new as fn ( & Table , & Table ) -> Box < Module > ) ;
types . insert ( " echo " , EchoModule ::new as fn ( & Table , & Table ) -> Box < Module > ) ;
types . insert ( " random " , RandomModule ::new as fn ( & Table , & Table ) -> Box < Module > ) ;
types . insert ( " pvn " , PvnModule ::new as fn ( & Table , & Table ) -> Box < Module > ) ;
types . insert ( " echobox " , EchoboxModule ::new as fn ( & Table , & Table ) -> Box < Module > ) ;
2017-02-26 17:17:22 -06:00
types . insert ( " autolink " , AutolinkModule ::new as fn ( & Table , & Table ) -> Box < Module > ) ;
2017-02-16 01:05:33 -06:00
ModuleLoader {
types : types
}
}
pub fn load_from_configuration ( & self , configuration : Table ) -> Result < BTreeMap < String , Box < Module > > , ModuleLoaderError > {
2017-02-26 02:44:53 -06:00
let general_config = configuration . get ( " general " )
. and_then ( | value | value . as_table ( ) )
. map ( | value | value . clone ( ) )
. unwrap_or_else ( | | BTreeMap ::new ( ) ) ;
2017-02-26 02:19:46 -06:00
configuration . into_iter ( ) . filter ( | & ( ref key , _ ) | {
key ! = " general "
} ) . map ( | ( key , value ) | {
2017-02-16 01:05:33 -06:00
match value . as_table ( ) {
Some ( table ) = > {
2017-02-26 02:44:53 -06:00
let module = self . load_single_module ( & key , & general_config , table ) ? ;
2017-02-16 01:05:33 -06:00
Result ::Ok ( ( key , module ) )
} ,
None = > Result ::Err ( ModuleLoaderError { message : format ! ( " Bad configuration parameters for module instance: {}. Configuration for a Module must be a table. " , key ) } )
}
} ) . collect ( )
}
2017-02-26 02:44:53 -06:00
pub fn load_single_module ( & self , name : & str , general_configuration : & Table , module_configuration : & Table ) -> Result < Box < Module > , ModuleLoaderError > {
2017-02-16 01:05:33 -06:00
/*
* The Module type defaults to the instance name ( in the tenquestionmarks configuration )
* but can explicitly be set by using the special " type " parameter .
* /
2017-02-26 02:44:53 -06:00
let module_type : & str = module_configuration . get ( " type " )
2017-02-16 01:05:33 -06:00
. and_then ( | value | value . as_str ( ) )
. unwrap_or ( name ) ;
match self . types . get ( module_type ) {
2017-02-26 02:44:53 -06:00
Some ( constructor ) = > Result ::Ok ( constructor ( general_configuration , module_configuration ) ) ,
2017-02-16 01:05:33 -06:00
None = > Result ::Err ( ModuleLoaderError { message : format ! ( " No such module type: {} " , module_type ) } )
}
}
}
#[ derive(Debug) ]
pub struct ModuleLoaderError {
message : String
}
impl Error for ModuleLoaderError {
fn description ( & self ) -> & str {
& self . message [ .. ]
}
}
impl fmt ::Display for ModuleLoaderError {
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
write! ( f , " ModuleLoaderError: {} " , self . message )
}
}