api: WIP: don't depend on a specific Body type

For a T which is not directly a Body or Response<Body> type
    #[api]
    fn foo() -> T;
should not require a specific Body type.

Signed-off-by: Wolfgang Bumiller <wry.git@bumiller.com>
This commit is contained in:
Wolfgang Bumiller 2019-06-23 11:41:27 +02:00
parent c8e11115d2
commit 916f9d945f
2 changed files with 35 additions and 26 deletions

View File

@ -18,6 +18,16 @@ pub trait ApiMethodInfo {
fn call(&self, params: Value) -> super::ApiFuture<Self::Body>;
}
impl<Body: 'static> dyn ApiMethodInfo<Body = Body> {
pub fn call_as<ToBody>(&self, params: Value) -> super::ApiFuture<ToBody>
where
Body: Into<ToBody>,
{
use futures::future::TryFutureExt;
Box::pin(self.call(params).map_ok(|res| res.map(|res| res.into())))
}
}
/// Shortcut to not having to type it out. This function signature is just a dummy and not yet
/// stabalized!
pub type CompleteFn = fn(&str) -> Vec<String>;
@ -289,3 +299,26 @@ impl<Body> ApiType for Response<Body> {
pub fn get_type_info<T: ApiType>() -> &'static TypeInfo {
T::type_info()
}
/// API methods can have different body types. For the CLI we don't care whether it is a
/// hyper::Body or a bytes::Bytes (also because we don't care for partia bodies etc.), so the
/// output needs to be wrapped to a common format. So basically the CLI will only ever see
/// `ApiOutput<Bytes>`.
pub trait UnifiedApiMethod<Body>: Send + Sync {
fn parameters(&self) -> &'static [Parameter];
fn call(&self, params: Value) -> super::ApiFuture<Body>;
}
impl<T: Send + Sync + 'static, Body> UnifiedApiMethod<Body> for T
where
T: ApiMethodInfo,
T::Body: 'static + Into<Body>,
{
fn parameters(&self) -> &'static [Parameter] {
ApiMethodInfo::parameters(self)
}
fn call(&self, params: Value) -> super::ApiFuture<Body> {
(self as &dyn ApiMethodInfo<Body = T::Body>).call_as(params)
}
}

View File

@ -8,9 +8,9 @@ use failure::{bail, format_err, Error};
use serde::Serialize;
use serde_json::Value;
use super::{ApiMethodInfo, ApiOutput, Parameter};
use super::{ApiMethodInfo, ApiOutput, Parameter, UnifiedApiMethod};
type MethodInfoRef = &'static dyn UnifiedApiMethod;
type MethodInfoRef = &'static dyn UnifiedApiMethod<Bytes>;
/// A CLI root node.
pub struct App {
@ -146,30 +146,6 @@ impl SubCommands {
}
}
/// API methods can have different body types. For the CLI we don't care whether it is a
/// hyper::Body or a bytes::Bytes (also because we don't care for partia bodies etc.), so the
/// output needs to be wrapped to a common format. So basically the CLI will only ever see
/// `ApiOutput<Bytes>`.
pub trait UnifiedApiMethod: Send + Sync {
fn parameters(&self) -> &'static [Parameter];
fn call(&self, params: Value) -> super::ApiFuture<Bytes>;
}
impl<T: Send + Sync> UnifiedApiMethod for T
where
T: ApiMethodInfo,
T::Body: 'static + Into<Bytes>,
{
fn parameters(&self) -> &'static [Parameter] {
ApiMethodInfo::parameters(self)
}
fn call(&self, params: Value) -> super::ApiFuture<Bytes> {
use futures::future::TryFutureExt;
Box::pin(ApiMethodInfo::call(self, params).map_ok(|res| res.map(|body| body.into())))
}
}
/// A reference to an API method. Note that when coming from the command line, it is possible to
/// match some parameters as positional parameters rather than argument switches, therefor this
/// contains an ordered list of positional parameters.