use http::uri::PathAndQuery;
use hyper::{Body, Method, Request, Uri};
use serde::Serialize;
use serde_json;
pub trait RequestType {
const METHOD: Method;
const PATH_AND_QUERY: &'static str;
}
pub trait IntoBody {
type Body: Serialize;
fn into_body(self) -> Self::Body;
}
pub trait IntoRequest: RequestType + IntoBody {
fn into_request(self, base_uri: Uri) -> Request<Body>;
}
type Key = Vec<u8>;
type Value = Vec<u8>;
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Get {
pub key: Key,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Del {
pub key: Key,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Set {
pub key: Key,
pub value: Value,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Cas {
pub key: Key,
pub old: Option<Value>,
pub new: Option<Value>,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Merge {
pub key: Key,
pub value: Value,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Flush;
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Iter;
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Scan {
pub key: Key,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct ScanRange {
pub start: Key,
pub end: Key,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Max;
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Pred {
pub key: Key,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct PredIncl {
pub key: Key,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Succ {
pub key: Key,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct SuccIncl {
pub key: Key,
}
impl RequestType for Get {
const METHOD: Method = Method::GET;
const PATH_AND_QUERY: &'static str = "/tree/entries/get";
}
impl RequestType for Del {
const METHOD: Method = Method::DELETE;
const PATH_AND_QUERY: &'static str = "/tree/entries/delete";
}
impl RequestType for Set {
const METHOD: Method = Method::POST;
const PATH_AND_QUERY: &'static str = "/tree/entries/set";
}
impl RequestType for Cas {
const METHOD: Method = Method::PUT;
const PATH_AND_QUERY: &'static str = "/tree/entries/cas";
}
impl RequestType for Merge {
const METHOD: Method = Method::POST;
const PATH_AND_QUERY: &'static str = "/tree/entries/merge";
}
impl RequestType for Flush {
const METHOD: Method = Method::PUT;
const PATH_AND_QUERY: &'static str = "/tree/entries/flush";
}
impl RequestType for Iter {
const METHOD: Method = Method::GET;
const PATH_AND_QUERY: &'static str = "/tree/entries/iter";
}
impl RequestType for Scan {
const METHOD: Method = Method::GET;
const PATH_AND_QUERY: &'static str = "/tree/entries/scan";
}
impl RequestType for ScanRange {
const METHOD: Method = Method::GET;
const PATH_AND_QUERY: &'static str = "/tree/entries/scan_range";
}
impl RequestType for Max {
const METHOD: Method = Method::GET;
const PATH_AND_QUERY: &'static str = "/tree/entries/max";
}
impl RequestType for Pred {
const METHOD: Method = Method::GET;
const PATH_AND_QUERY: &'static str = "/tree/entries/pred";
}
impl RequestType for PredIncl {
const METHOD: Method = Method::GET;
const PATH_AND_QUERY: &'static str = "/tree/entries/pred_incl";
}
impl RequestType for Succ {
const METHOD: Method = Method::GET;
const PATH_AND_QUERY: &'static str = "/tree/entries/succ";
}
impl RequestType for SuccIncl {
const METHOD: Method = Method::GET;
const PATH_AND_QUERY: &'static str = "/tree/entries/succ_incl";
}
impl IntoBody for Get {
type Body = Self;
fn into_body(self) -> Self::Body { self }
}
impl IntoBody for Del {
type Body = Self;
fn into_body(self) -> Self::Body { self }
}
impl IntoBody for Set {
type Body = Self;
fn into_body(self) -> Self::Body { self }
}
impl IntoBody for Cas {
type Body = Self;
fn into_body(self) -> Self::Body { self }
}
impl IntoBody for Merge {
type Body = Self;
fn into_body(self) -> Self::Body { self }
}
impl IntoBody for Flush {
type Body = Self;
fn into_body(self) -> Self::Body { self }
}
impl IntoBody for Iter {
type Body = Self;
fn into_body(self) -> Self::Body { self }
}
impl IntoBody for Scan {
type Body = Self;
fn into_body(self) -> Self::Body { self }
}
impl IntoBody for ScanRange {
type Body = Self;
fn into_body(self) -> Self::Body { self }
}
impl IntoBody for Max {
type Body = Self;
fn into_body(self) -> Self::Body { self }
}
impl IntoBody for Pred {
type Body = Self;
fn into_body(self) -> Self::Body { self }
}
impl IntoBody for PredIncl {
type Body = Self;
fn into_body(self) -> Self::Body { self }
}
impl IntoBody for Succ {
type Body = Self;
fn into_body(self) -> Self::Body { self }
}
impl IntoBody for SuccIncl {
type Body = Self;
fn into_body(self) -> Self::Body { self }
}
impl<T> IntoRequest for T
where
T: RequestType + IntoBody,
{
fn into_request(self, base_uri: Uri) -> Request<Body> {
let method = T::METHOD;
let uri = uri_with_path(base_uri, T::PATH_AND_QUERY);
let body = self.into_body();
let body_json = serde_json::to_vec(&body).expect("failed to serialize request body");
Request::builder()
.method(method)
.uri(uri)
.body(body_json.into())
.expect("attempted to construct invalid request")
}
}
fn uri_with_path(uri: Uri, path: &str) -> Uri {
let mut parts = uri.into_parts();
let path_and_query = path
.parse::<PathAndQuery>()
.expect("failed to parse path and query for request URI");
parts.path_and_query = Some(path_and_query);
Uri::from_parts(parts)
.expect("failed to construct request URI from parts")
}
pub fn from<T>(base_uri: Uri, req: T) -> Request<Body>
where
T: IntoRequest,
{
req.into_request(base_uri)
}
pub fn get(base_uri: Uri, key: Key) -> Request<Body> {
from(base_uri, Get { key })
}
pub fn del(base_uri: Uri, key: Key) -> Request<Body> {
from(base_uri, Del { key })
}
pub fn set(base_uri: Uri, key: Key, value: Value) -> Request<Body> {
from(base_uri, Set { key, value })
}
pub fn iter(base_uri: Uri) -> Request<Body> {
from(base_uri, Iter)
}
pub fn scan(base_uri: Uri, key: Key) -> Request<Body> {
from(base_uri, Scan { key })
}
pub fn scan_range(base_uri: Uri, start: Key, end: Key) -> Request<Body> {
from(base_uri, ScanRange { start, end })
}
pub fn max(base_uri: Uri) -> Request<Body> {
from(base_uri, Max)
}
pub fn pred(base_uri: Uri, key: Key) -> Request<Body> {
from(base_uri, Pred { key })
}
pub fn pred_incl(base_uri: Uri, key: Key) -> Request<Body> {
from(base_uri, PredIncl { key })
}
pub fn succ(base_uri: Uri, key: Key) -> Request<Body> {
from(base_uri, Succ { key })
}
pub fn succ_incl(base_uri: Uri, key: Key) -> Request<Body> {
from(base_uri, SuccIncl { key })
}
pub fn cas(base_uri: Uri, key: Key, old: Option<Value>, new: Option<Value>) -> Request<Body> {
from(base_uri, Cas { key, old, new })
}
pub fn merge(base_uri: Uri, key: Key, value: Value) -> Request<Body> {
from(base_uri, Merge { key, value })
}
pub fn flush(base_uri: Uri) -> Request<Body> {
from(base_uri, Flush)
}