feat: add bitcode encoding/decoding to server functions (#4376)

This commit is contained in:
arpad voros
2025-10-24 12:42:01 -04:00
committed by GitHub
parent 9dd5501b1a
commit 43359694b6
9 changed files with 114 additions and 2 deletions

43
Cargo.lock generated
View File

@@ -283,6 +283,12 @@ version = "1.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
[[package]]
name = "arrayvec"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "async-executor"
version = "1.13.3"
@@ -487,6 +493,30 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bitcode"
version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "648bd963d2e5d465377acecfb4b827f9f553b6bc97a8f61715779e9ed9e52b74"
dependencies = [
"arrayvec",
"bitcode_derive",
"bytemuck",
"glam",
"serde",
]
[[package]]
name = "bitcode_derive"
version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffebfc2d28a12b262c303cb3860ee77b91bd83b1f20f0bd2a9693008e2f55a9e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.106",
]
[[package]]
name = "bitflags"
version = "2.9.4"
@@ -552,6 +582,12 @@ dependencies = [
"syn 2.0.106",
]
[[package]]
name = "bytemuck"
version = "1.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4"
[[package]]
name = "byteorder"
version = "1.5.0"
@@ -1306,6 +1342,12 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "glam"
version = "0.30.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e12d847aeb25f41be4c0ec9587d624e9cd631bc007a8fd7ce3f5851e064c6460"
[[package]]
name = "glib"
version = "0.20.12"
@@ -3429,6 +3471,7 @@ dependencies = [
"actix-ws",
"axum",
"base64",
"bitcode",
"bytes",
"ciborium",
"const-str",

View File

@@ -134,6 +134,7 @@ inventory = { default-features = false, version = "0.3.21" }
config = { default-features = false, version = "0.15.14" }
camino = { default-features = false, version = "1.2.1" }
ciborium = { default-features = false, version = "0.2.2" }
bitcode = { default-features = false, version = "0.6.6" }
multer = { default-features = false, version = "3.1.0" }
leptos-spin-macro = { default-features = false, version = "0.2.0" }
sledgehammer_utils = { default-features = false, version = "0.3.1" }

View File

@@ -88,6 +88,7 @@ ssr = [
]
nightly = ["leptos_macro/nightly", "reactive_graph/nightly", "tachys/nightly"]
rkyv = ["server_fn/rkyv", "leptos_server/rkyv"]
bitcode = ["server_fn/bitcode"]
serde-lite = ["server_fn/serde-lite", "leptos_server/serde-lite"]
cbor = ["server_fn/cbor"]
msgpack = ["server_fn/msgpack"]
@@ -152,6 +153,7 @@ denylist = [
"trace-component-props",
"spin",
"islands",
"bitcode",
"serde-lite",
"cbor",
"msgpack",
@@ -163,7 +165,6 @@ skip_feature_sets = [
["csr", "hydrate"],
["ssr", "hydrate"],
["serde", "serde-lite"],
["serde-lite", "miniserde"],
["serde", "miniserde"],
["serde", "rkyv"],
["miniserde", "rkyv"],

View File

@@ -64,6 +64,7 @@ http-body-util = { optional = true, workspace = true, default-features = true }
rkyv = { optional = true, workspace = true, default-features = true }
rmp-serde = { optional = true, workspace = true, default-features = true }
base64 = { workspace = true, default-features = true }
bitcode = { optional = true, workspace = true, default-features = true }
# client
gloo-net = { optional = true, workspace = true, default-features = true }
@@ -126,6 +127,7 @@ cbor = ["dep:ciborium"]
rkyv = ["dep:rkyv"]
msgpack = ["dep:rmp-serde"]
postcard = ["dep:postcard"]
bitcode = ["dep:bitcode"]
default-tls = ["reqwest?/default-tls"]
rustls = ["reqwest?/rustls-tls", "tokio-tungstenite?/rustls"]
reqwest = ["dep:reqwest", "dep:tokio-tungstenite", "dep:tokio"]

View File

@@ -0,0 +1,49 @@
use super::{Patch, Post, Put};
use crate::{ContentType, Decodes, Encodes, Format, FormatType};
use bytes::Bytes;
/// Serializes and deserializes with [`bitcode`].
pub struct BitcodeEncoding;
impl ContentType for BitcodeEncoding {
const CONTENT_TYPE: &'static str = "application/bitcode";
}
impl FormatType for BitcodeEncoding {
const FORMAT_TYPE: Format = Format::Binary;
}
impl<T> Encodes<T> for BitcodeEncoding
where
T: bitcode::Encode,
{
type Error = std::convert::Infallible;
fn encode(value: &T) -> Result<Bytes, Self::Error> {
Ok(Bytes::from(bitcode::encode(value)))
}
}
impl<T> Decodes<T> for BitcodeEncoding
where
T: bitcode::DecodeOwned,
{
type Error = bitcode::Error;
fn decode(bytes: Bytes) -> Result<T, Self::Error> {
bitcode::decode(bytes.as_ref())
}
}
/// Pass arguments and receive responses using `bitcode` in a `POST` request.
pub type Bitcode = Post<BitcodeEncoding>;
/// Pass arguments and receive responses using `bitcode` in the body of a `PATCH` request.
/// **Note**: Browser support for `PATCH` requests without JS/WASM may be poor.
/// Consider using a `POST` request if functionality without JS/WASM is required.
pub type PatchBitcode = Patch<BitcodeEncoding>;
/// Pass arguments and receive responses using `bitcode` in the body of a `PUT` request.
/// **Note**: Browser support for `PUT` requests without JS/WASM may be poor.
/// Consider using a `POST` request if functionality without JS/WASM is required.
pub type PutBitcode = Put<BitcodeEncoding>;

View File

@@ -50,6 +50,11 @@ mod postcard;
#[cfg(feature = "postcard")]
pub use postcard::*;
#[cfg(feature = "bitcode")]
mod bitcode;
#[cfg(feature = "bitcode")]
pub use bitcode::*;
mod patch;
pub use patch::*;
mod post;

View File

@@ -133,6 +133,8 @@ pub use ::bytes as bytes_export;
#[doc(hidden)]
pub use ::http as http_export;
use base64::{engine::general_purpose::STANDARD_NO_PAD, DecodeError, Engine};
#[cfg(feature = "bitcode")]
pub use bitcode;
// re-exported to make it possible to implement a custom Client without adding a separate
// dependency on `bytes`
pub use bytes::Bytes;

View File

@@ -10,7 +10,8 @@
feature = "multipart",
feature = "serde-lite",
feature = "cbor",
feature = "msgpack"
feature = "msgpack",
feature = "bitcode",
))
))]

View File

@@ -331,6 +331,7 @@ impl ServerFnCall {
enum PathInfo {
Serde,
Rkyv,
Bitcode,
None,
}
@@ -341,6 +342,12 @@ impl ServerFnCall {
Clone, #server_fn_path::rkyv::Archive, #server_fn_path::rkyv::Serialize, #server_fn_path::rkyv::Deserialize
},
),
Some("Bitcode") => (
PathInfo::Bitcode,
quote! {
Clone, #server_fn_path::bitcode::Encode, #server_fn_path::bitcode::Decode
},
),
Some("MultipartFormData")
| Some("Streaming")
| Some("StreamingText") => (PathInfo::None, quote! {}),
@@ -376,6 +383,7 @@ impl ServerFnCall {
#[serde(crate = #serde_path)]
}
}
PathInfo::Bitcode => quote! {},
PathInfo::Rkyv => quote! {},
PathInfo::None => quote! {},
};