Skip to content

Commit

Permalink
allow type paths for input/output, and properly namespace built-in en…
Browse files Browse the repository at this point in the history
…codings
  • Loading branch information
gbj committed Jan 10, 2024
1 parent 25832c1 commit d4bea99
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 35 deletions.
1 change: 0 additions & 1 deletion examples/todo_app_sqlite/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ leptos = { path = "../../leptos", features = ["nightly"] }
leptos_actix = { path = "../../integrations/actix", optional = true }
leptos_meta = { path = "../../meta", features = ["nightly"] }
leptos_router = { path = "../../router", features = ["nightly"] }
server_fn = { path = "../../server_fn", features = ["cbor"] }
log = "0.4.17"
simple_logger = "4.0.0"
gloo = { git = "https://github.com/rustwasm/gloo" }
Expand Down
9 changes: 5 additions & 4 deletions examples/todo_app_sqlite/src/todo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ cfg_if! {
}
}

#[server(GetTodos, "/api")]
// This is an example of leptos's server functions using an alternative CBOR encoding. Both the function arguments being sent
// to the server and the server response will be encoded with CBOR. Good for binary data that doesn't encode well via the default methods
#[server(encoding = "Cbor")]
pub async fn get_todos() -> Result<Vec<Todo>, ServerFnError> {
// this is just an example of how to access server context injected in the handlers
let req = use_context::<actix_web::HttpRequest>();
Expand All @@ -43,9 +45,8 @@ pub async fn get_todos() -> Result<Vec<Todo>, ServerFnError> {

Ok(todos)
}
// This is an example of leptos's server functions using an alternative CBOR encoding. Both the function arguments being sent
// to the server and the server response will be encoded with CBOR. Good for binary data that doesn't encode well via the default methods
#[server(AddTodo, "/api", "Cbor")]

#[server]
pub async fn add_todo(title: String) -> Result<(), ServerFnError> {
let mut conn = db().await?;

Expand Down
102 changes: 72 additions & 30 deletions server_fn_macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use syn::{
parse::{Parse, ParseStream},
punctuated::Punctuated,
spanned::Spanned,
*,
Type, *,
};

/// The implementation of the `server_fn` macro.
Expand Down Expand Up @@ -71,23 +71,43 @@ pub fn server_macro_impl(
input,
output,
fn_path,
builtin_encoding,
} = args;
let prefix = prefix.unwrap_or_else(|| Literal::string(default_path));
let fn_path = fn_path.unwrap_or_else(|| Literal::string(""));
let input_ident = input
.as_ref()
.map(ToString::to_string)
.unwrap_or_else(|| "PostUrl".to_string());
let input = input.map(|n| n.to_token_stream()).unwrap_or_else(|| {
quote! {
#server_fn_path::codec::PostUrl
}
});
let output = output.map(|n| n.to_token_stream()).unwrap_or_else(|| {
quote! {
#server_fn_path::codec::Json
let input_ident = match &input {
Some(Type::Path(path)) => {
path.path.segments.last().map(|seg| seg.ident.to_string())
}
});
None => Some("PostUrl".to_string()),
_ => None,
};
let input = input
.map(|n| {
if builtin_encoding {
quote! { #server_fn_path::codec::#n }
} else {
n.to_token_stream()
}
})
.unwrap_or_else(|| {
quote! {
#server_fn_path::codec::PostUrl
}
});
let output = output
.map(|n| {
if builtin_encoding {
quote! { #server_fn_path::codec::#n }
} else {
n.to_token_stream()
}
})
.unwrap_or_else(|| {
quote! {
#server_fn_path::codec::Json
}
});
// default to PascalCase version of function name if no struct name given
let struct_name = struct_name.unwrap_or_else(|| {
let upper_camel_case_name = Converter::new()
Expand Down Expand Up @@ -316,10 +336,10 @@ pub fn server_macro_impl(
}
};

let (is_serde, derives) = match input_ident.as_str() {
"Rkyv" => todo!("implement derives for Rkyv"),
"MultipartFormData" => (false, quote! {}),
"SerdeLite" => (
let (is_serde, derives) = match input_ident.as_deref() {
Some("Rkyv") => todo!("implement derives for Rkyv"),
Some("MultipartFormData") => (false, quote! {}),
Some("SerdeLite") => (
true,
quote! {
Clone, #server_fn_path::serde_lite::Serialize, #server_fn_path::serde_lite::Deserialize
Expand Down Expand Up @@ -470,6 +490,21 @@ pub fn server_macro_impl(
})
}

fn type_from_ident(ident: Ident) -> Type {
let mut segments = Punctuated::new();
segments.push(PathSegment {
ident,
arguments: PathArguments::None,
});
Type::Path(TypePath {
qself: None,
path: Path {
leading_colon: None,
segments,
},
})
}

#[derive(Debug)]
struct Middleware {
expr: syn::Expr,
Expand Down Expand Up @@ -555,9 +590,10 @@ fn err_type(return_ty: &Type) -> Result<Option<&GenericArgument>> {
struct ServerFnArgs {
struct_name: Option<Ident>,
prefix: Option<Literal>,
input: Option<Ident>,
output: Option<Ident>,
input: Option<Type>,
output: Option<Type>,
fn_path: Option<Literal>,
builtin_encoding: bool,
}

impl Parse for ServerFnArgs {
Expand All @@ -569,8 +605,8 @@ impl Parse for ServerFnArgs {
let mut fn_path: Option<Literal> = None;

// new arguments: can only be keyed by name
let mut input: Option<Ident> = None;
let mut output: Option<Ident> = None;
let mut input: Option<Type> = None;
let mut output: Option<Type> = None;

let mut use_key_and_value = false;
let mut arg_pos = 0;
Expand Down Expand Up @@ -698,23 +734,28 @@ impl Parse for ServerFnArgs {
}

// parse legacy encoding into input/output
let mut builtin_encoding = false;
if let Some(encoding) = encoding {
match encoding.to_string().to_lowercase().as_str() {
"\"url\"" => {
input = syn::parse_quote!(PostUrl);
output = syn::parse_quote!(Json);
input = Some(type_from_ident(syn::parse_quote!(PostUrl)));
output = Some(type_from_ident(syn::parse_quote!(Json)));
builtin_encoding = true;
}
"\"cbor\"" => {
input = syn::parse_quote!(Cbor);
output = syn::parse_quote!(Cbor);
input = Some(type_from_ident(syn::parse_quote!(Cbor)));
output = Some(type_from_ident(syn::parse_quote!(Cbor)));
builtin_encoding = true;
}
"\"getcbor\"" => {
input = syn::parse_quote!(GetUrl);
output = syn::parse_quote!(Cbor);
input = Some(type_from_ident(syn::parse_quote!(GetUrl)));
output = Some(type_from_ident(syn::parse_quote!(Cbor)));
builtin_encoding = true;
}
"\"getjson\"" => {
input = syn::parse_quote!(GetUrl);
output = syn::parse_quote!(Json);
input = Some(type_from_ident(syn::parse_quote!(GetUrl)));
output = Some(type_from_ident(syn::parse_quote!(Json)));
builtin_encoding = true;
}
_ => {
return Err(syn::Error::new(
Expand All @@ -731,6 +772,7 @@ impl Parse for ServerFnArgs {
input,
output,
fn_path,
builtin_encoding,
})
}
}
Expand Down

0 comments on commit d4bea99

Please sign in to comment.