mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
get rkyv working and work on custom encoding example
This commit is contained in:
parent
4366d786ac
commit
35e8e74dcf
13 changed files with 302 additions and 60 deletions
|
@ -25,6 +25,8 @@ tower-http = { version = "0.5", features = ["fs"], optional = true }
|
|||
tokio = { version = "1", features = ["full"], optional = true }
|
||||
thiserror = "1.0"
|
||||
wasm-bindgen = "0.2"
|
||||
serde_toml = "0.0.1"
|
||||
toml = "0.8.8"
|
||||
|
||||
[features]
|
||||
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
|
||||
|
|
|
@ -1,9 +1,18 @@
|
|||
use crate::error_template::ErrorTemplate;
|
||||
use http::{Request, Response};
|
||||
use leptos::{html::Input, *};
|
||||
use leptos_meta::*;
|
||||
use leptos_meta::{Link, Stylesheet};
|
||||
use leptos_router::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use server_fn::codec::SerdeLite;
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use server_fn::{
|
||||
codec::{
|
||||
Encoding, FromReq, FromRes, GetUrl, IntoReq, IntoRes, Rkyv, SerdeLite,
|
||||
},
|
||||
error::NoCustomError,
|
||||
request::{browser::BrowserRequest, BrowserMockReq, ClientReq, Req},
|
||||
response::{browser::BrowserResponse, ClientRes, Res},
|
||||
rkyv::AlignedVec,
|
||||
};
|
||||
#[cfg(feature = "ssr")]
|
||||
use std::sync::{
|
||||
atomic::{AtomicU8, Ordering},
|
||||
|
@ -37,6 +46,10 @@ pub fn HomePage() -> impl IntoView {
|
|||
<SpawnLocal/>
|
||||
<WithAnAction/>
|
||||
<WithActionForm/>
|
||||
<h2>"Alternative Encodings"</h2>
|
||||
<ServerFnArgumentExample/>
|
||||
<RkyvExample/>
|
||||
<CustomEncoding/>
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,7 +168,15 @@ pub fn WithAnAction() -> impl IntoView {
|
|||
<button
|
||||
on:click=move |_| {
|
||||
let text = input_ref.get().unwrap().value();
|
||||
action.dispatch(AddRow { text });
|
||||
action.dispatch(text);
|
||||
// note: technically, this `action` takes `AddRow` (the server fn type) as its
|
||||
// argument
|
||||
//
|
||||
// however, `.dispatch()` takes `impl Into<I>`, and for any one-argument server
|
||||
// functions, `From<_>` is implemented between the server function type and the
|
||||
// type of this single argument
|
||||
//
|
||||
// so `action.dispatch(text)` means `action.dispatch(AddRow { text })`
|
||||
}
|
||||
>
|
||||
Submit
|
||||
|
@ -195,8 +216,202 @@ pub fn WithActionForm() -> impl IntoView {
|
|||
</ActionForm>
|
||||
<p>You submitted: {move || format!("{:?}", action.input().get())}</p>
|
||||
<p>The result was: {move || format!("{:?}", action.value().get())}</p>
|
||||
<Transition>
|
||||
<Transition>archive underaligned: need alignment 4 but have alignment 1
|
||||
<p>Total rows: {row_count}</p>
|
||||
</Transition>
|
||||
}
|
||||
}
|
||||
|
||||
/// The plain `#[server]` macro gives sensible defaults for the settings needed to create a server
|
||||
/// function, but those settings can also be customized. For example, you can set a specific unique
|
||||
/// path rather than the hashed path, or you can choose a different combination of input and output
|
||||
/// encodings.
|
||||
///
|
||||
/// Arguments to the server macro can be specified as named key-value pairs, like `name = value`.
|
||||
#[server(
|
||||
// this server function will be exposed at /api2/custom_path
|
||||
prefix = "/api2",
|
||||
endpoint = "custom_path",
|
||||
// it will take its arguments as a URL-encoded GET request (useful for caching)
|
||||
input = GetUrl,
|
||||
// it will return its output using SerdeLite
|
||||
// (this needs to be enabled with the `serde-lite` feature on the `server_fn` crate
|
||||
output = SerdeLite
|
||||
)]
|
||||
pub async fn length_of_input(input: String) -> Result<usize, ServerFnError> {
|
||||
// insert a simulated wait
|
||||
tokio::time::sleep(std::time::Duration::from_millis(250)).await;
|
||||
Ok(input.len())
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn ServerFnArgumentExample() -> impl IntoView {
|
||||
let input_ref = NodeRef::<Input>::new();
|
||||
let (result, set_result) = create_signal(0);
|
||||
|
||||
view! {
|
||||
<h3>Custom arguments to the <code>#[server]</code> " macro"</h3>
|
||||
<p>
|
||||
</p>
|
||||
<input node_ref=input_ref placeholder="Type something here."/>
|
||||
<button
|
||||
on:click=move |_| {
|
||||
let value = input_ref.get().unwrap().value();
|
||||
spawn_local(async move {
|
||||
let length = length_of_input(value).await.unwrap_or(0);
|
||||
set_result(length);
|
||||
});
|
||||
}
|
||||
>
|
||||
Click to see length
|
||||
</button>
|
||||
<p>Length is {result}</p>
|
||||
}
|
||||
}
|
||||
|
||||
/// `server_fn` supports a wide variety of input and output encodings, each of which can be
|
||||
/// referred to as a PascalCased struct name
|
||||
/// - Toml
|
||||
/// - Cbor
|
||||
/// - Rkyv
|
||||
/// - etc.
|
||||
#[server(
|
||||
input = Rkyv,
|
||||
output = Rkyv
|
||||
)]
|
||||
pub async fn rkyv_example(input: String) -> Result<String, ServerFnError> {
|
||||
// insert a simulated wait
|
||||
tokio::time::sleep(std::time::Duration::from_millis(250)).await;
|
||||
Ok(input.to_ascii_uppercase())
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn RkyvExample() -> impl IntoView {
|
||||
let input_ref = NodeRef::<Input>::new();
|
||||
let (input, set_input) = create_signal(String::new());
|
||||
let rkyv_result = create_resource(input, rkyv_example);
|
||||
|
||||
view! {
|
||||
<h3>Using <code>rkyv</code> encoding</h3>
|
||||
<p>
|
||||
</p>
|
||||
<input node_ref=input_ref placeholder="Type something here."/>
|
||||
<button
|
||||
on:click=move |_| {
|
||||
let value = input_ref.get().unwrap().value();
|
||||
set_input(value);
|
||||
}
|
||||
>
|
||||
Click to see length
|
||||
</button>
|
||||
<p>{input}</p>
|
||||
<Transition>
|
||||
{rkyv_result}
|
||||
</Transition>
|
||||
}
|
||||
}
|
||||
|
||||
/// Server function encodings are just types that implement a few traits.
|
||||
/// This means that you can implement your own encodings, by implementing those traits!
|
||||
///
|
||||
/// Here, we'll create a custom encoding that serializes and deserializes the server fn
|
||||
/// using TOML. Why would you ever want to do this? I don't know, but you can!
|
||||
struct Toml;
|
||||
|
||||
impl Encoding for Toml {
|
||||
const CONTENT_TYPE: &'static str = "application/toml";
|
||||
const METHOD: Method = Method::POST;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
type Request = BrowserMockReq;
|
||||
#[cfg(feature = "ssr")]
|
||||
type Request = http::Request<axum::body::Body>;
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
type Response = BrowserMockRes;
|
||||
#[cfg(feature = "ssr")]
|
||||
type Response = http::Response<axum::body::Body>;
|
||||
|
||||
impl<T> IntoReq<Toml, BrowserRequest, NoCustomError> for T {
|
||||
fn into_req(
|
||||
self,
|
||||
path: &str,
|
||||
accepts: &str,
|
||||
) -> Result<BrowserRequest, ServerFnError> {
|
||||
let data = toml::to_string(&self)
|
||||
.map_err(|e| ServerFnError::Serialization(e.to_string()))?;
|
||||
Request::try_new_post(path, Toml::CONTENT_TYPE, accepts, data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromReq<Toml, Request, NoCustomError> for T
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
async fn from_req(req: Request) -> Result<Self, ServerFnError> {
|
||||
let string_data = req.try_into_string().await?;
|
||||
toml::from_str::<Self>(&string_data)
|
||||
.map_err(|e| ServerFnError::Args(e.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoRes<Toml, Response, NoCustomError> for T
|
||||
where
|
||||
T: Serialize + Send,
|
||||
{
|
||||
async fn into_res(self) -> Result<Response, ServerFnError> {
|
||||
let data = toml::to_string(&self)
|
||||
.map_err(|e| ServerFnError::Serialization(e.to_string()))?;
|
||||
Response::try_from_string(Toml::CONTENT_TYPE, data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<e> FromRes<Toml, BrowserResponse, NoCustomError> for T
|
||||
where
|
||||
T: DeserializeOwned + Send,
|
||||
{
|
||||
async fn from_res(res: BrowserResponse) -> Result<Self, ServerFnError> {
|
||||
let data = res.try_into_string().await?;
|
||||
toml::from_str(&data)
|
||||
.map_err(|e| ServerFnError::Deserialization(e.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
#[server(
|
||||
input = Toml,
|
||||
output = Toml
|
||||
)]
|
||||
pub async fn why_not(
|
||||
foo: String,
|
||||
bar: String,
|
||||
) -> Result<String, ServerFnError> {
|
||||
// insert a simulated wait
|
||||
tokio::time::sleep(std::time::Duration::from_millis(250)).await;
|
||||
Ok(foo + &bar)
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn CustomEncoding() -> impl IntoView {
|
||||
let input_ref = NodeRef::<Input>::new();
|
||||
let (result, set_result) = create_signal(0);
|
||||
|
||||
view! {
|
||||
<h3>Custom encodings</h3>
|
||||
<p>
|
||||
"This example creates a custom encoding that sends server fn data using TOML. Why? Well... why not?"
|
||||
</p>
|
||||
<input node_ref=input_ref placeholder="Type something here."/>
|
||||
<button
|
||||
on:click=move |_| {
|
||||
let value = input_ref.get().unwrap().value();
|
||||
spawn_local(async move {
|
||||
let new_value = why_not(value, ", but in TOML!!!".to_string());
|
||||
set_result(new_value);
|
||||
});
|
||||
}
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
<p>{result}</p>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,8 +93,8 @@ where
|
|||
any(debug_assertions, feature = "ssr"),
|
||||
tracing::instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
pub fn dispatch(&self, input: I) {
|
||||
self.0.with_value(|a| a.dispatch(input))
|
||||
pub fn dispatch(&self, input: impl Into<I>) {
|
||||
self.0.with_value(|a| a.dispatch(input.into()))
|
||||
}
|
||||
|
||||
/// Create an [Action].
|
||||
|
|
|
@ -16,7 +16,7 @@ impl Encoding for Cbor {
|
|||
const METHOD: Method = Method::POST;
|
||||
}
|
||||
|
||||
impl<CustErr, T, Request> IntoReq<CustErr, Request, Cbor> for T
|
||||
impl<CustErr, T, Request> IntoReq<Cbor, Request, CustErr> for T
|
||||
where
|
||||
Request: ClientReq<CustErr>,
|
||||
T: Serialize + Send,
|
||||
|
@ -38,7 +38,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<CustErr, T, Request> FromReq<CustErr, Request, Cbor> for T
|
||||
impl<CustErr, T, Request> FromReq<Cbor, Request, CustErr> for T
|
||||
where
|
||||
Request: Req<CustErr> + Send + 'static,
|
||||
T: DeserializeOwned,
|
||||
|
@ -50,7 +50,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<CustErr, T, Response> IntoRes<CustErr, Response, Cbor> for T
|
||||
impl<CustErr, T, Response> IntoRes<Cbor, Response, CustErr> for T
|
||||
where
|
||||
Response: Res<CustErr>,
|
||||
T: Serialize + Send,
|
||||
|
@ -63,7 +63,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<CustErr, T, Response> FromRes<CustErr, Response, Cbor> for T
|
||||
impl<CustErr, T, Response> FromRes<Cbor, Response, CustErr> for T
|
||||
where
|
||||
Response: ClientRes<CustErr> + Send,
|
||||
T: DeserializeOwned + Send,
|
||||
|
|
|
@ -15,7 +15,7 @@ impl Encoding for Json {
|
|||
const METHOD: Method = Method::POST;
|
||||
}
|
||||
|
||||
impl<CustErr, T, Request> IntoReq<CustErr, Request, Json> for T
|
||||
impl<CustErr, T, Request> IntoReq<Json, Request, CustErr> for T
|
||||
where
|
||||
Request: ClientReq<CustErr>,
|
||||
T: Serialize + Send,
|
||||
|
@ -31,7 +31,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<CustErr, T, Request> FromReq<CustErr, Request, Json> for T
|
||||
impl<CustErr, T, Request> FromReq<Json, Request, CustErr> for T
|
||||
where
|
||||
Request: Req<CustErr> + Send + 'static,
|
||||
T: DeserializeOwned,
|
||||
|
@ -43,7 +43,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<CustErr, T, Response> IntoRes<CustErr, Response, Json> for T
|
||||
impl<CustErr, T, Response> IntoRes<Json, Response, CustErr> for T
|
||||
where
|
||||
Response: Res<CustErr>,
|
||||
T: Serialize + Send,
|
||||
|
@ -55,7 +55,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<CustErr, T, Response> FromRes<CustErr, Response, Json> for T
|
||||
impl<CustErr, T, Response> FromRes<Json, Response, CustErr> for T
|
||||
where
|
||||
Response: ClientRes<CustErr> + Send,
|
||||
T: DeserializeOwned + Send,
|
||||
|
|
|
@ -61,7 +61,7 @@ pub use stream::*;
|
|||
/// For example, here’s the implementation for [`Json`].
|
||||
///
|
||||
/// ```rust
|
||||
/// impl<CustErr, T, Request> IntoReq<CustErr, Request, Json> for T
|
||||
/// impl<CustErr, T, Request> IntoReq<Json, Request, CustErr> for T
|
||||
/// where
|
||||
/// Request: ClientReq<CustErr>,
|
||||
/// T: Serialize + Send,
|
||||
|
@ -79,7 +79,7 @@ pub use stream::*;
|
|||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub trait IntoReq<CustErr, Request, Encoding> {
|
||||
pub trait IntoReq<Encoding, Request, CustErr> {
|
||||
/// Attempts to serialize the arguments into an HTTP request.
|
||||
fn into_req(
|
||||
self,
|
||||
|
@ -99,7 +99,7 @@ pub trait IntoReq<CustErr, Request, Encoding> {
|
|||
/// For example, here’s the implementation for [`Json`].
|
||||
///
|
||||
/// ```rust
|
||||
/// impl<CustErr, T, Request> FromReq<CustErr, Request, Json> for T
|
||||
/// impl<CustErr, T, Request> FromReq<Json, Request, CustErr> for T
|
||||
/// where
|
||||
/// // require the Request implement `Req`
|
||||
/// Request: Req<CustErr> + Send + 'static,
|
||||
|
@ -117,7 +117,7 @@ pub trait IntoReq<CustErr, Request, Encoding> {
|
|||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub trait FromReq<CustErr, Request, Encoding>
|
||||
pub trait FromReq<Encoding, Request, CustErr>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
|
@ -138,7 +138,7 @@ where
|
|||
/// For example, here’s the implementation for [`Json`].
|
||||
///
|
||||
/// ```rust
|
||||
/// impl<CustErr, T, Response> IntoRes<CustErr, Response, Json> for T
|
||||
/// impl<CustErr, T, Response> IntoRes<Json, Response, CustErr> for T
|
||||
/// where
|
||||
/// Response: Res<CustErr>,
|
||||
/// T: Serialize + Send,
|
||||
|
@ -152,7 +152,7 @@ where
|
|||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub trait IntoRes<CustErr, Response, Encoding> {
|
||||
pub trait IntoRes<Encoding, Response, CustErr> {
|
||||
/// Attempts to serialize the output into an HTTP response.
|
||||
fn into_res(
|
||||
self,
|
||||
|
@ -171,7 +171,7 @@ pub trait IntoRes<CustErr, Response, Encoding> {
|
|||
/// For example, here’s the implementation for [`Json`].
|
||||
///
|
||||
/// ```rust
|
||||
/// impl<CustErr, T, Response> FromRes<CustErr, Response, Json> for T
|
||||
/// impl<CustErr, T, Response> FromRes<Json, Response, CustErr> for T
|
||||
/// where
|
||||
/// Response: ClientRes<CustErr> + Send,
|
||||
/// T: DeserializeOwned + Send,
|
||||
|
@ -187,7 +187,7 @@ pub trait IntoRes<CustErr, Response, Encoding> {
|
|||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub trait FromRes<CustErr, Response, Encoding>
|
||||
pub trait FromRes<Encoding, Response, CustErr>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
|
|
|
@ -56,7 +56,7 @@ impl From<FormData> for MultipartData {
|
|||
}
|
||||
}
|
||||
|
||||
impl<CustErr, T, Request> IntoReq<CustErr, Request, MultipartFormData> for T
|
||||
impl<CustErr, T, Request> IntoReq<MultipartFormData, Request, CustErr> for T
|
||||
where
|
||||
Request: ClientReq<CustErr, FormData = BrowserFormData>,
|
||||
T: Into<MultipartData>,
|
||||
|
@ -75,7 +75,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<CustErr, T, Request> FromReq<CustErr, Request, MultipartFormData> for T
|
||||
impl<CustErr, T, Request> FromReq<MultipartFormData, Request, CustErr> for T
|
||||
where
|
||||
Request: Req<CustErr> + Send + 'static,
|
||||
T: From<MultipartData>,
|
||||
|
|
|
@ -20,7 +20,7 @@ impl Encoding for Rkyv {
|
|||
const METHOD: Method = Method::POST;
|
||||
}
|
||||
|
||||
impl<CustErr, T, Request> IntoReq<CustErr, Request, Rkyv> for T
|
||||
impl<CustErr, T, Request> IntoReq<Rkyv, Request, CustErr> for T
|
||||
where
|
||||
Request: ClientReq<CustErr>,
|
||||
T: Serialize<AllocSerializer<1024>> + Send,
|
||||
|
@ -40,7 +40,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<CustErr, T, Request> FromReq<CustErr, Request, Rkyv> for T
|
||||
impl<CustErr, T, Request> FromReq<Rkyv, Request, CustErr> for T
|
||||
where
|
||||
Request: Req<CustErr> + Send + 'static,
|
||||
T: Serialize<AllocSerializer<1024>> + Send,
|
||||
|
@ -50,12 +50,12 @@ where
|
|||
{
|
||||
async fn from_req(req: Request) -> Result<Self, ServerFnError<CustErr>> {
|
||||
let body_bytes = req.try_into_bytes().await?;
|
||||
rkyv::from_bytes::<T>(&body_bytes)
|
||||
rkyv::from_bytes::<T>(body_bytes.as_ref())
|
||||
.map_err(|e| ServerFnError::Args(e.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<CustErr, T, Response> IntoRes<CustErr, Response, Rkyv> for T
|
||||
impl<CustErr, T, Response> IntoRes<Rkyv, Response, CustErr> for T
|
||||
where
|
||||
Response: Res<CustErr>,
|
||||
T: Serialize<AllocSerializer<1024>> + Send,
|
||||
|
@ -71,7 +71,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<CustErr, T, Response> FromRes<CustErr, Response, Rkyv> for T
|
||||
impl<CustErr, T, Response> FromRes<Rkyv, Response, CustErr> for T
|
||||
where
|
||||
Response: ClientRes<CustErr> + Send,
|
||||
T: Serialize<AllocSerializer<1024>> + Send,
|
||||
|
|
|
@ -15,7 +15,7 @@ impl Encoding for SerdeLite {
|
|||
const METHOD: Method = Method::POST;
|
||||
}
|
||||
|
||||
impl<CustErr, T, Request> IntoReq<CustErr, Request, SerdeLite> for T
|
||||
impl<CustErr, T, Request> IntoReq<SerdeLite, Request, CustErr> for T
|
||||
where
|
||||
Request: ClientReq<CustErr>,
|
||||
T: Serialize + Send,
|
||||
|
@ -35,7 +35,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<CustErr, T, Request> FromReq<CustErr, Request, SerdeLite> for T
|
||||
impl<CustErr, T, Request> FromReq<SerdeLite, Request, CustErr> for T
|
||||
where
|
||||
Request: Req<CustErr> + Send + 'static,
|
||||
T: Deserialize,
|
||||
|
@ -50,7 +50,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<CustErr, T, Response> IntoRes<CustErr, Response, SerdeLite> for T
|
||||
impl<CustErr, T, Response> IntoRes<SerdeLite, Response, CustErr> for T
|
||||
where
|
||||
Response: Res<CustErr>,
|
||||
T: Serialize + Send,
|
||||
|
@ -66,7 +66,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<CustErr, T, Response> FromRes<CustErr, Response, SerdeLite> for T
|
||||
impl<CustErr, T, Response> FromRes<SerdeLite, Response, CustErr> for T
|
||||
where
|
||||
Response: ClientRes<CustErr> + Send,
|
||||
T: Deserialize + Send,
|
||||
|
|
|
@ -19,7 +19,7 @@ impl Encoding for Streaming {
|
|||
const METHOD: Method = Method::POST;
|
||||
}
|
||||
|
||||
/* impl<CustErr, T, Request> IntoReq<CustErr, Request, ByteStream> for T
|
||||
/* impl<CustErr, T, Request> IntoReq<ByteStream, Request, CustErr> for T
|
||||
where
|
||||
Request: ClientReq<CustErr>,
|
||||
T: Stream<Item = Bytes> + Send,
|
||||
|
@ -29,7 +29,7 @@ where
|
|||
}
|
||||
} */
|
||||
|
||||
/* impl<CustErr, T, Request> FromReq<CustErr, Request, ByteStream> for T
|
||||
/* impl<CustErr, T, Request> FromReq<ByteStream, Request, CustErr> for T
|
||||
where
|
||||
Request: Req<CustErr> + Send + 'static,
|
||||
T: Stream<Item = Bytes> + Send,
|
||||
|
@ -65,7 +65,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<CustErr, Response> IntoRes<CustErr, Response, Streaming>
|
||||
impl<CustErr, Response> IntoRes<Streaming, Response, CustErr>
|
||||
for ByteStream<CustErr>
|
||||
where
|
||||
Response: Res<CustErr>,
|
||||
|
@ -76,7 +76,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<CustErr, Response> FromRes<CustErr, Response, Streaming> for ByteStream
|
||||
impl<CustErr, Response> FromRes<Streaming, Response, CustErr> for ByteStream
|
||||
where
|
||||
Response: ClientRes<CustErr> + Send,
|
||||
{
|
||||
|
@ -122,7 +122,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<CustErr, Response> IntoRes<CustErr, Response, StreamingText>
|
||||
impl<CustErr, Response> IntoRes<StreamingText, Response, CustErr>
|
||||
for TextStream<CustErr>
|
||||
where
|
||||
Response: Res<CustErr>,
|
||||
|
@ -136,7 +136,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<CustErr, Response> FromRes<CustErr, Response, StreamingText> for TextStream
|
||||
impl<CustErr, Response> FromRes<StreamingText, Response, CustErr> for TextStream
|
||||
where
|
||||
Response: ClientRes<CustErr> + Send,
|
||||
{
|
||||
|
|
|
@ -17,7 +17,7 @@ impl Encoding for GetUrl {
|
|||
const METHOD: Method = Method::GET;
|
||||
}
|
||||
|
||||
impl<CustErr, T, Request> IntoReq<CustErr, Request, GetUrl> for T
|
||||
impl<CustErr, T, Request> IntoReq<GetUrl, Request, CustErr> for T
|
||||
where
|
||||
Request: ClientReq<CustErr>,
|
||||
T: Serialize + Send,
|
||||
|
@ -33,7 +33,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<CustErr, T, Request> FromReq<CustErr, Request, GetUrl> for T
|
||||
impl<CustErr, T, Request> FromReq<GetUrl, Request, CustErr> for T
|
||||
where
|
||||
Request: Req<CustErr> + Send + 'static,
|
||||
T: DeserializeOwned,
|
||||
|
@ -51,7 +51,7 @@ impl Encoding for PostUrl {
|
|||
const METHOD: Method = Method::POST;
|
||||
}
|
||||
|
||||
impl<CustErr, T, Request> IntoReq<CustErr, Request, PostUrl> for T
|
||||
impl<CustErr, T, Request> IntoReq<PostUrl, Request, CustErr> for T
|
||||
where
|
||||
Request: ClientReq<CustErr>,
|
||||
T: Serialize + Send,
|
||||
|
@ -67,7 +67,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<CustErr, T, Request> FromReq<CustErr, Request, PostUrl> for T
|
||||
impl<CustErr, T, Request> FromReq<PostUrl, Request, CustErr> for T
|
||||
where
|
||||
Request: Req<CustErr> + Send + 'static,
|
||||
T: DeserializeOwned,
|
||||
|
|
|
@ -132,6 +132,8 @@ use once_cell::sync::Lazy;
|
|||
use redirect::RedirectHook;
|
||||
use request::Req;
|
||||
use response::{ClientRes, Res};
|
||||
#[cfg(feature = "rkyv")]
|
||||
pub use rkyv;
|
||||
#[doc(hidden)]
|
||||
pub use serde;
|
||||
#[doc(hidden)]
|
||||
|
@ -173,11 +175,11 @@ pub use xxhash_rust;
|
|||
pub trait ServerFn
|
||||
where
|
||||
Self: Send
|
||||
+ FromReq<Self::Error, Self::ServerRequest, Self::InputEncoding>
|
||||
+ FromReq<Self::InputEncoding, Self::ServerRequest, Self::Error>
|
||||
+ IntoReq<
|
||||
Self::Error,
|
||||
<Self::Client as Client<Self::Error>>::Request,
|
||||
Self::InputEncoding,
|
||||
<Self::Client as Client<Self::Error>>::Request,
|
||||
Self::Error,
|
||||
>,
|
||||
{
|
||||
/// A unique path for the server function’s API endpoint, relative to the host, including its prefix.
|
||||
|
@ -198,11 +200,11 @@ where
|
|||
///
|
||||
/// This needs to be converted into `ServerResponse` on the server side, and converted
|
||||
/// *from* `ClientResponse` when received by the client.
|
||||
type Output: IntoRes<Self::Error, Self::ServerResponse, Self::OutputEncoding>
|
||||
type Output: IntoRes<Self::OutputEncoding, Self::ServerResponse, Self::Error>
|
||||
+ FromRes<
|
||||
Self::Error,
|
||||
<Self::Client as Client<Self::Error>>::Response,
|
||||
Self::OutputEncoding,
|
||||
<Self::Client as Client<Self::Error>>::Response,
|
||||
Self::Error,
|
||||
> + Send;
|
||||
|
||||
/// The [`Encoding`] used in the request for arguments into the server function.
|
||||
|
|
|
@ -130,6 +130,12 @@ pub fn server_macro_impl(
|
|||
}
|
||||
FnArg::Typed(t) => t,
|
||||
};
|
||||
|
||||
// strip `mut`, which is allowed in fn args but not in struct fields
|
||||
if let Pat::Ident(ident) = &mut *typed_arg.pat {
|
||||
ident.mutability = None;
|
||||
}
|
||||
|
||||
// allow #[server(default)] on fields — TODO is this documented?
|
||||
let mut default = false;
|
||||
let mut other_attrs = Vec::new();
|
||||
|
@ -332,27 +338,45 @@ pub fn server_macro_impl(
|
|||
}
|
||||
};
|
||||
|
||||
let (is_serde, derives) = match input_ident.as_deref() {
|
||||
Some("Rkyv") => todo!("implement derives for Rkyv"),
|
||||
Some("MultipartFormData") => (false, quote! {}),
|
||||
enum PathInfo {
|
||||
Serde,
|
||||
Rkyv,
|
||||
None,
|
||||
}
|
||||
|
||||
let (path, derives) = match input_ident.as_deref() {
|
||||
Some("Rkyv") => (
|
||||
PathInfo::Rkyv,
|
||||
quote! {
|
||||
Clone, #server_fn_path::rkyv::Archive, #server_fn_path::rkyv::Serialize, #server_fn_path::rkyv::Deserialize
|
||||
},
|
||||
),
|
||||
Some("MultipartFormData") => (PathInfo::None, quote! {}),
|
||||
Some("SerdeLite") => (
|
||||
true,
|
||||
PathInfo::Serde,
|
||||
quote! {
|
||||
Clone, #server_fn_path::serde_lite::Serialize, #server_fn_path::serde_lite::Deserialize
|
||||
},
|
||||
),
|
||||
_ => (
|
||||
true,
|
||||
PathInfo::Serde,
|
||||
quote! {
|
||||
Clone, #server_fn_path::serde::Serialize, #server_fn_path::serde::Deserialize
|
||||
},
|
||||
),
|
||||
};
|
||||
let serde_path = is_serde.then(|| {
|
||||
quote! {
|
||||
let addl_path = match path {
|
||||
PathInfo::Serde => quote! {
|
||||
#[serde(crate = #serde_path)]
|
||||
},
|
||||
PathInfo::Rkyv => {
|
||||
let rkyv_path = format!("{server_fn_path}::rkyv");
|
||||
quote! {
|
||||
#[archive(crate = #rkyv_path, check_bytes)]
|
||||
}
|
||||
}
|
||||
});
|
||||
PathInfo::None => quote! {},
|
||||
};
|
||||
|
||||
// TODO reqwest
|
||||
let client = quote! {
|
||||
|
@ -429,7 +453,6 @@ pub fn server_macro_impl(
|
|||
} else {
|
||||
#server_fn_path::const_format::concatcp!(
|
||||
#prefix,
|
||||
"/",
|
||||
#fn_path
|
||||
)
|
||||
}
|
||||
|
@ -453,7 +476,7 @@ pub fn server_macro_impl(
|
|||
#args_docs
|
||||
#docs
|
||||
#[derive(Debug, #derives)]
|
||||
#serde_path
|
||||
#addl_path
|
||||
pub struct #struct_name {
|
||||
#(#fields),*
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue