use algo::{AlgoInput, AlgoOutput, JsonValue};
use std::error::Error as StdError;
use error::{Error, ErrorKind, ResultExt};
use json;
#[cfg(feature="with-serde")]
use serde::Deserialize;
#[cfg(feature="with-rustc-serialize")]
use rustc_serialize::Decodable;
pub trait DecodedEntryPoint: Default {
#[cfg(feature="with-serde")]
type Input: Deserialize;
#[cfg(feature="with-rustc-serialize")]
#[deprecated(since="2.1.0", note="rustc-serialize has been deprecated")]
type Input: Decodable;
#[allow(unused_variables)]
fn apply_decoded(&self, input: Self::Input) -> Result<AlgoOutput, Box<StdError>>;
}
impl<T> EntryPoint for T
where T: DecodedEntryPoint
{
fn apply(&self, input: AlgoInput) -> Result<AlgoOutput, Box<StdError>> {
match input.as_json() {
Some(obj) => {
let decoded = json::decode_value(obj.into_owned())
.chain_err(|| "failed to parse input as JSON into the expected type")?;
self.apply_decoded(decoded)
}
None => Err(Error::from(ErrorKind::UnsupportedInput).into()),
}
}
}
pub trait EntryPoint: Default {
#[allow(unused_variables)]
fn apply_str(&self, text: &str) -> Result<AlgoOutput, Box<StdError>> {
Err(Error::from(ErrorKind::UnsupportedInput).into())
}
#[allow(unused_variables)]
fn apply_json(&self, json: &JsonValue) -> Result<AlgoOutput, Box<StdError>> {
Err(Error::from(ErrorKind::UnsupportedInput).into())
}
#[allow(unused_variables)]
fn apply_bytes(&self, bytes: &[u8]) -> Result<AlgoOutput, Box<StdError>> {
Err(Error::from(ErrorKind::UnsupportedInput).into())
}
fn apply(&self, input: AlgoInput) -> Result<AlgoOutput, Box<StdError>> {
match input {
AlgoInput::Text(ref text) => {
match self.apply_str(text) {
Err(err) => {
match err.downcast::<Error>().map(|err| *err) {
Ok(Error(ErrorKind::UnsupportedInput, _)) => {
match input.as_json() {
Some(json) => self.apply_json(&json),
None => Err(Error::from(ErrorKind::UnsupportedInput).into()),
}
}
Ok(err) => Err(err.into()),
Err(err) => Err(err.into()),
}
}
ret => ret,
}
}
AlgoInput::Json(ref json) => {
match self.apply_json(json) {
Err(err) => {
match err.downcast::<Error>().map(|err| *err) {
Ok(Error(ErrorKind::UnsupportedInput, _)) => {
match input.as_string() {
Some(text) => self.apply_str(text),
None => {
Err(Error::from(ErrorKind::UnsupportedInput).into()).into()
}
}
}
Ok(err) => Err(err.into()),
Err(err) => Err(err.into()),
}
}
ret => ret,
}
}
AlgoInput::Binary(ref bytes) => self.apply_bytes(bytes),
}
}
}