#![cfg_attr(not(feature = "std"), no_std)]
#![allow(async_fn_in_trait)]
extern crate alloc;
use alloc::vec::Vec;
pub use prost::Message;
pub mod serde_helpers;
pub use serde_json;
pub use serde_qs;
pub mod server {
use super::*;
pub use anyhow::Error;
use core::marker::PhantomData;
use derive_more::Display;
#[derive(Display, Message)]
pub struct ProtoError {
#[prost(string, tag = "1")]
pub message: ::prost::alloc::string::String,
}
impl ProtoError {
pub fn new(message: impl Into<String>) -> ProtoError {
ProtoError {
message: message.into(),
}
}
}
pub trait NamedService: Service {
const NAME: &'static str;
}
pub trait Service {
type Methods: AsRef<[&'static str]>;
fn methods() -> Self::Methods;
async fn dispatch_request(
self,
path: &str,
data: impl AsRef<[u8]>,
json: bool,
query: bool,
) -> Result<Vec<u8>, Error>;
}
pub struct ComposedService<A, T> {
app: A,
_marker: PhantomData<T>,
}
impl<T, A> ComposedService<A, T> {
pub fn new(app: A) -> Self {
Self {
app,
_marker: PhantomData,
}
}
}
impl<A, T> From<A> for ComposedService<A, T> {
fn from(app: A) -> Self {
Self::new(app)
}
}
macro_rules! impl_service_for_tuple {
() => {
impl<A> Service for ComposedService<A, ()> {
type Methods = Vec<&'static str>;
fn methods() -> Vec<&'static str> {
Vec::new()
}
async fn dispatch_request(
self,
path: &str,
_data: impl AsRef<[u8]>,
_json: bool,
_query: bool,
) -> Result<Vec<u8>, Error> {
anyhow::bail!("Service not found: {path}")
}
}
};
( $head:ident $(, $tail:ident)* $(,)*) => {
impl<A, $head, $( $tail, )*> Service for ComposedService<A, ($head, $( $tail, )*)>
where
$head: NamedService + From<A>,
$( $tail: NamedService + From<A>, )*
{
type Methods = Vec<&'static str>;
fn methods() -> Self::Methods {
let mut methods = Vec::new();
methods.extend_from_slice($head::methods().as_ref());
$(
methods.extend_from_slice($tail::methods().as_ref());
)*
methods
}
async fn dispatch_request(
self,
path: &str,
data: impl AsRef<[u8]>,
json: bool,
query: bool,
) -> Result<Vec<u8>, Error> {
let service_name = path.split('.').next().unwrap_or_default();
if service_name == $head::NAME {
return $head::from(self.app).dispatch_request(path, data, json, query).await;
}
$(
if service_name == $tail::NAME {
return $tail::from(self.app).dispatch_request(path, data, json, query).await;
}
)*
anyhow::bail!("Service not found: {service_name}")
}
}
impl_service_for_tuple!($($tail,)*);
};
}
impl_service_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
}
pub mod client {
use serde::{de::DeserializeOwned, Serialize};
use super::*;
pub use anyhow::Error;
pub trait RequestClient {
async fn request<T, R>(&self, path: &str, body: T) -> Result<R, Error>
where
T: Message + Serialize,
R: Message + DeserializeOwned;
}
}
pub mod codec {
use super::*;
pub use parity_scale_codec as scale;
pub fn encode_message_to_vec(msg: &impl Message) -> Vec<u8> {
let mut buf = Vec::with_capacity(msg.encoded_len());
msg.encode_raw(&mut buf);
buf
}
}