Skip to content

Instantly share code, notes, and snippets.

@anowell
Last active November 13, 2016 16:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anowell/f7b1251c123309a5515f411a03d55572 to your computer and use it in GitHub Desktop.
Save anowell/f7b1251c123309a5515f411a03d55572 to your computer and use it in GitHub Desktop.
First draft experiment at reducing boilerplate for algorithm entrypoint
/*
Example usage:
Note: in all of these cases, the return value must be `Result<T, E>` where:
- `T` has a conversion to `AlgoOutput` (e.g. String, Vec<u8>, JsonValue, (), or anything Serializeable)
- `E` has a conversion to `Box<Error>` (e.g. String or any custom type that `impl Error`)
-------------Text-----------------------
algo_entrypoint! { text => hello }
fn hello(input: &str) -> Result<String, String> {
Ok(format!("Hello {}", input))
}
-------------JSON-----------------------
algo_entrypoint! { json => foo }
fn foo(input: JsonValue) -> Result<JsonValue, String> {
Ok(input)
}
-------------Binary-----------------------
algo_entrypoint! { bytes => foo }
fn foo(input: &[u8]) -> Result<u64, String> {
Ok(input.len() as u64)
}
-------------Auto-Decode-----------------------
#[derive(RustcDecodable)]
struct MyInput { field: String };
#[derive(RustcEncodable)]
struct MyOutput { field: u32 };
algo_entrypoint! { MyInput => foo }
fn foo(input: MyInput) -> Result<MyOutput, String> {
Ok(MyOutput {
field: input.field.len() as u32
})
}
-------------One-time init with state-----------------------
pub struct Algo { uuid: String };
algo_entrypoint! { text => Algo::hello }
impl Algo {
fn hello(&self, input: &str) -> Result<String, String> {
Ok(format!("Hello {} - {}", input, self.uuid))
}
}
impl Default for Algo {
fn default() -> Algo {
Algo { uuid: uuid::gen_uuid() }
}
}
*/
#[macro_export]
macro_rules! algo_entrypoint {
// Helpers for recursively implementing text/bytes/JsonValue/AlgoInput
($t:ty, $apply:ident, Algo::$method:ident) => {
impl EntryPoint for Algo {
fn $apply(&self, input: $t) -> Result<AlgoOutput, Box<::std::error::Error>> {
self.$method(input).map(AlgoOutput::from).map_err(|err| err.into())
}
}
};
($t:ty, $apply:ident, $p:path) => {
#[derive(Default)] pub struct Algo;
impl EntryPoint for Algo {
fn $apply(&self, input: $t) -> Result<AlgoOutput, Box<::std::error::Error>> {
$p(input).map(AlgoOutput::from).map_err(|err| err.into())
}
}
};
// Implement EntryPoint to call methods on `Algo`
(text => Algo::$i:ident) => {
algo_entrypoint!(&str, apply_str, Algo::$i);
};
(bytes => Algo::$i:ident) => {
algo_entrypoint!(&[u8], apply_bytes, Algo::$i);
};
(json => Algo::$i:ident) => {
algo_entrypoint!(::algorithmia::algo::JsonValue, apply_json, Algo::$i);
};
(AlgoInput => Algo::$i:ident) => {
algo_entrypoint!(::algorithmia::AlgoInput, apply, Algo::$i);
};
($t:ty => Algo::$i:ident) => {
impl DecodedEntryPoint for Algo {
type Input = $t;
fn apply_bytes(&self, input: $t) -> Result<AlgoOutput, Box<::std::error::Error>> {
self.$i(input).map(AlgoOutput::from).map_err(|err| err.into())
}
}
};
// Implement EntryPoint to call free functions
(text => $i:ident) => {
algo_entrypoint!(&str, apply_str, $i);
};
(bytes => $i:ident) => {
algo_entrypoint!(&[u8], apply_bytes, $i);
};
(json => $i:ident) => {
algo_entrypoint!(::algorithmia::algo::JsonValue, apply_json, $i);
};
(AlgoInput => $i:ident) => {
algo_entrypoint!(::algorithmia::AlgoInput, apply, $i);
};
($t:ty => $p:path) => {
#[derive(Default)] pub struct Algo;
impl DecodedEntryPoint for Algo {
type Input = $t;
fn apply_decoded(&self, input: $t) -> Result<AlgoOutput, Box<::std::error::Error>> {
$p(text).map(AlgoOutput::from).map_err(|err| err.into())
}
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment