use std::ops;
use std::marker::PhantomData;
use super::{BoxContext, Context, Device, ExtensionPackage, Framework, Hardware, HardwareKind, Unextended};
use super::{Error, ErrorKind, Result};
use utility::{self, TryDefault};
#[derive(Debug)]
pub struct Backend<X = Unextended> {
framework: Box<Framework>,
context: Box<Context<Package = X>>,
}
impl<X> Backend<X> where X: ExtensionPackage {
pub fn new<F>() -> Result<Self> where F: BoxContext<X> + Framework + TryDefault<Err = Error> {
let framework = F::try_default()?;
let selection = framework.available_hardware();
Self::with(framework, selection)
}
pub fn with<F>(fwrk: F, selection: Vec<Hardware>) -> Result<Self>
where F: BoxContext<X> + Framework {
let mut framework = Box::new(fwrk);
let context = framework.enclose(selection)?;
Ok(Backend { framework, context })
}
pub fn try_from<F>(co: BackendConfig<F, X>) -> Result<Self> where F: BoxContext<X> + Framework {
let BackendConfig { framework, hardware, kind, .. } = co;
let mut backend = Self::with(framework, hardware)?;
backend.select(|h| h.kind == kind)?;
Ok(backend)
}
pub fn set_active(&mut self, index: usize) -> Result {
self.context.set_active(index)
}
pub fn select<P>(&mut self, mut predicate: P) -> Result where P: FnMut(&Hardware) -> bool {
let opt_index = self.framework.selection()
.iter()
.enumerate()
.filter(|&(_, hardware)| predicate(hardware))
.map(|(index, _)| index)
.nth(0);
match opt_index {
Some(index) => self.set_active(index),
_ => {
let message = "There are no devices matching the specified criteria.";
Err(Error::new(ErrorKind::Framework { name: self.framework.name() }, message))
}
}
}
}
impl<X> ops::Deref for Backend<X> where X: ExtensionPackage {
type Target = X::Extension;
fn deref<'a>(&'a self) -> &'a X::Extension {
self.context.extension()
}
}
impl<X> utility::Has<Device> for Backend<X> where X: ExtensionPackage {
fn get_ref(&self) -> &Device {
self.context.active_device()
}
}
#[derive(Debug)]
pub struct BackendConfig<F, X> {
framework: F,
hardware: Vec<Hardware>,
kind: HardwareKind,
extension: PhantomData<X>,
}
impl<F, X> BackendConfig<F, X> {
pub fn new(framework: F, hardware: Vec<Hardware>, kind: HardwareKind) -> Self {
BackendConfig { framework, hardware, kind, extension: PhantomData }
}
}