use std::marker::PhantomData;
use std::sync::Arc;
use orpc_procedure::{DynInput, ErasedSchema, ProcedureError};
use serde::Serialize;
use serde::de::DeserializeOwned;
use crate::error::ORPCError;
pub trait Schema: Send + Sync + 'static {
type Input: DeserializeOwned + Send;
type Output: Serialize + Send;
fn validate(&self, input: Self::Input) -> Result<Self::Output, ORPCError>;
fn json_schema(&self) -> serde_json::Value;
fn is_passthrough(&self) -> bool {
false
}
fn into_erased(self) -> Box<dyn ErasedSchema>
where
Self: Sized,
{
Box::new(SchemaAdapter(self))
}
}
pub struct Identity<T>(PhantomData<T>);
impl<T> Identity<T> {
pub fn new() -> Self {
Identity(PhantomData)
}
}
impl<T> Default for Identity<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: DeserializeOwned + Serialize + Send + Sync + 'static> Schema for Identity<T> {
type Input = T;
type Output = T;
fn validate(&self, input: T) -> Result<T, ORPCError> {
Ok(input)
}
fn json_schema(&self) -> serde_json::Value {
serde_json::json!({})
}
fn is_passthrough(&self) -> bool {
true
}
}
pub(crate) struct SchemaAdapter<S: Schema>(pub S);
impl<S: Schema + 'static> ErasedSchema for SchemaAdapter<S> {
fn json_schema(&self) -> serde_json::Value {
self.0.json_schema()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
pub(crate) type InputValidator =
Arc<dyn Fn(DynInput) -> Result<DynInput, ProcedureError> + Send + Sync>;
pub(crate) fn make_input_validator() -> Option<InputValidator> {
None
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn identity_passthrough() {
let schema = Identity::<String>::new();
let result = schema.validate("hello".to_string());
assert_eq!(result.unwrap(), "hello");
}
#[test]
fn identity_json_schema() {
let schema = Identity::<u32>::new();
assert_eq!(schema.json_schema(), serde_json::json!({}));
}
#[test]
fn schema_adapter_erased() {
let schema = Identity::<u32>::new();
let erased: Box<dyn ErasedSchema> = Box::new(SchemaAdapter(schema));
assert_eq!(erased.json_schema(), serde_json::json!({}));
}
}