use rinf::RustSignal;
use serde::{Deserialize, Serialize};
pub trait IntoResponse {
type Response: RustSignal;
fn into_response(self) -> Self::Response;
}
mod private {
use super::{Deserialize, RustSignal, Serialize};
#[derive(Serialize, Deserialize)]
pub enum Either<A, B> {
A(A),
B(B),
}
impl<A, B> RustSignal for Either<A, B>
where
A: RustSignal,
B: RustSignal,
{
fn send_signal_to_dart(&self) {
match self {
Either::A(a) => a.send_signal_to_dart(),
Either::B(b) => b.send_signal_to_dart(),
}
}
}
}
#[derive(Serialize)]
pub struct DontSend<T = ()>(pub T);
impl<T> RustSignal for DontSend<T>
where
T: Serialize,
{
fn send_signal_to_dart(&self) {}
}
impl<T> IntoResponse for DontSend<T>
where
T: Serialize,
{
type Response = Self;
fn into_response(self) -> Self::Response {
self
}
}
impl IntoResponse for () {
type Response = DontSend;
fn into_response(self) -> Self::Response {
DontSend(())
}
}
impl<T, E> IntoResponse for Result<T, E>
where
T: IntoResponse,
E: IntoResponse,
{
type Response = private::Either<T::Response, E::Response>;
fn into_response(self) -> Self::Response {
match self {
Ok(ok) => private::Either::A(ok.into_response()),
Err(err) => private::Either::B(err.into_response()),
}
}
}
impl<T> IntoResponse for Option<T>
where
T: IntoResponse,
{
type Response = private::Either<T::Response, DontSend>;
fn into_response(self) -> Self::Response {
match self {
Some(val) => private::Either::A(val.into_response()),
None => private::Either::B(DontSend(())),
}
}
}
impl<T> IntoResponse for (T,)
where
T: RustSignal,
{
type Response = T;
fn into_response(self) -> Self::Response {
self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unit_into_response_compiles() {
let resp = ().into_response();
resp.send_signal_to_dart();
}
#[test]
fn dont_send_round_trip() {
let ok: Result<(), DontSend<&'static str>> = Ok(());
let _ = ok.into_response();
let err: Result<(), DontSend<&'static str>> = Err(DontSend("oops"));
let _ = err.into_response();
}
#[test]
fn option_into_response() {
let some = Some(()).into_response();
some.send_signal_to_dart();
let none: Option<()> = None;
let resp = none.into_response();
resp.send_signal_to_dart();
}
}