diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a12fb58..2cc0813 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -32,11 +32,11 @@ jobs:
- name: Clippy
run: cargo clippy --features prost,serde,docs,math --tests -- -D warnings
- name: Run tests (general)
- run: cargo test --features math,docs,ssr,prost,json_serde,msgpack_serde,bincode_serde
+ run: cargo test --features math,docs,ssr,prost,json_serde,msgpack_serde,bincode_serde,base64
- name: Run tests (axum)
- run: cargo test --features math,docs,ssr,prost,json_serde,msgpack_serde,bincode_serde,axum --doc use_cookie::use_cookie
+ run: cargo test --features math,docs,ssr,prost,json_serde,msgpack_serde,bincode_serde,base64,axum --doc use_cookie::use_cookie
- name: Run tests (actix)
- run: cargo test --features math,docs,ssr,prost,json_serde,msgpack_serde,bincode_serde,actix --doc use_cookie::use_cookie
+ run: cargo test --features math,docs,ssr,prost,json_serde,msgpack_serde,bincode_serde,base64,actix --doc use_cookie::use_cookie
#### mdbook
- name: Install mdbook I
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index a04226a..559a729 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -25,8 +25,8 @@ jobs:
- name: Clippy
run: cargo clippy --features prost,serde,docs,math --tests -- -D warnings
- name: Run tests (general)
- run: cargo test --features math,docs,ssr,prost,json_serde,msgpack_serde,bincode_serde
+ run: cargo test --features math,docs,ssr,prost,json_serde,msgpack_serde,bincode_serde,base64
- name: Run tests (axum)
- run: cargo test --features math,docs,ssr,prost,json_serde,msgpack_serde,bincode_serde,axum --doc use_cookie::use_cookie
+ run: cargo test --features math,docs,ssr,prost,json_serde,msgpack_serde,bincode_serde,base64,axum --doc use_cookie::use_cookie
- name: Run tests (actix)
- run: cargo test --features math,docs,ssr,prost,json_serde,msgpack_serde,bincode_serde,actix --doc use_cookie::use_cookie
+ run: cargo test --features math,docs,ssr,prost,json_serde,msgpack_serde,bincode_serde,base64,actix --doc use_cookie::use_cookie
diff --git a/.idea/leptos-use.iml b/.idea/leptos-use.iml
index 66b8cda..7d56fcb 100644
--- a/.idea/leptos-use.iml
+++ b/.idea/leptos-use.iml
@@ -76,6 +76,7 @@
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c4a94f4..a9d18f2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,22 +5,59 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
-### Changes 🔥
+### New Features 🚀
+- There are now binary codecs in addition to string codecs.
+ - `FromToBytesCodec`
+ - `WebpackSerdeCodec` (requires feature `webpack_serde`)
+ - `BincodeSerdeCodec` (requires feature `bincode_serde`)
+ - `ProstCodec` (requires feature `prost`) (see also the section "Breaking Changes 🛠" below)
+- Every binary codec can be used as a string codec with the `Base64` wrapper which encodes the binary data as a base64
+ string.
+ - This required feature `base64`
+ - It can be wrapped for example like this: `Base64`.
+- There is now an `OptionCodec` wrapper that allows to wrap any string codec that encodes `T` to encode `Option`.
+ - Use it like this: `OptionCodec>`.
- `ElementMaybeSignal` is now implemented for `websys::HtmlElement` (thanks to @blorbb).
- `UseStorageOptions` now has `delay_during_hydration` which has to be used when you conditionally show parts of
the DOM controlled by a value from storage. This leads to hydration errors which can be fixed by setting this new
option to `true`.
- `cookie::SameSite` is now re-exported
-- Fixed typo in compiler error messages in `use_cookie` (thanks to @SleeplessOne1917).
+- New book chapter about codecs
### Breaking Changes 🛠
-- `UseStorageOptions` no longer accepts a `codec` value because this is already provided as a generic parameter to
- the respective function calls.
-- `UseWebsocketOptions::reconnect_limit` is now `ReconnectLimit` instead of `u64`. Use `ReconnectLimit::Infinite` for
- infinite retries or `ReconnectLimit::Limited(...)` for limited retries.
-- `StringCodec::decode` now takes a `&str` instead of a `String`.
+- `UseStorageOptions` and `UseEventSourceOptions` no longer accept a `codec` value because this is already provided as a
+ generic parameter to the respective function calls.
+- Codecs have been refactored. There are now two traits that codecs implement: `Encoder` and `Decoder`. The
+ trait `StringCodec` is gone. The methods are now associated methods and their params now always take references.
+ - `JsonCodec` has been renamed to `JsonSerdeCodec`.
+ - The feature to enable this codec is now called `json_serde` instead of just `serde`.
+ - `ProstCodec` now encodes as binary data. If you want to keep using it with string data you can wrap it like
+ this: `Base64`. You have to enable both features `prost` and `base64` for this.
+- `use_websocket`:
+ - `UseWebsocketOptions` has been renamed to `UseWebSocketOptions` (uppercase S) to be consistent with the return
+ type.
+ - `UseWebSocketOptions::reconnect_limit` and `UseEventSourceOptions::reconnect_limit` is now `ReconnectLimit`
+ instead
+ of `u64`. Use `ReconnectLimit::Infinite` for infinite retries or `ReconnectLimit::Limited(...)` for limited
+ retries.
+ - `use_websocket` now uses codecs to send typed messages over the network.
+ - When calling you have give type parameters for the message type and the
+ codec: `use_websocket::`
+ - You can use binary or string codecs.
+ - The `UseWebSocketReturn::send` closure now takes a `&T` which is encoded using the codec.
+ - The `UseWebSocketReturn::message` signal now returns an `Option` which is decoded using the codec.
+ - `UseWebSocketReturn::send_bytes` and `UseWebSocketReturn::message_bytes` are gone.
+ - `UseWebSocketOptions::on_message` and `UseWebSocketOptions::on_message_bytes` have been renamed
+ to `on_message_raw` and `on_message_raw_bytes`.
+ - The new `UseWebSocketOptions::on_message` takes a `&T`.
+ - `UseWebSocketOptions::on_error` now takes a `UseWebSocketError` instead of a `web_sys::Event`.
+
+### Fixes 🍕
+
+- Fixed auto-reconnect in `use_websocket`
+- Fixed typo in compiler error messages in `use_cookie` (thanks to @SleeplessOne1917).
## [0.10.10] - 2024-05-10
diff --git a/docs/book/src/SUMMARY.md b/docs/book/src/SUMMARY.md
index 51ca13f..d43fb8a 100644
--- a/docs/book/src/SUMMARY.md
+++ b/docs/book/src/SUMMARY.md
@@ -4,6 +4,7 @@
[Get Started](get_started.md)
[Element Parameters](element_parameters.md)
[Server-Side Rendering](server_side_rendering.md)
+[Encoding and Decoding Data](codecs.md)
[Changelog](changelog.md)
[Functions](functions.md)
@@ -65,6 +66,7 @@
- [use_event_source](network/use_event_source.md)
- [use_websocket](network/use_websocket.md)
+
# Animation
@@ -94,6 +96,7 @@
- [use_sorted](iterable/use_sorted.md)
# Utilities
+
- [is_err](utilities/is_err.md)
- [is_none](utilities/is_none.md)
- [is_ok](utilities/is_ok.md)
diff --git a/examples/use_storage/Cargo.toml b/examples/use_storage/Cargo.toml
index a4ba692..98ebbf3 100644
--- a/examples/use_storage/Cargo.toml
+++ b/examples/use_storage/Cargo.toml
@@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] }
console_error_panic_hook = "0.1"
console_log = "1"
log = "0.4"
-leptos-use = { path = "../..", features = ["docs", "prost", "serde"] }
+leptos-use = { path = "../..", features = ["docs", "json_serde"] }
web-sys = "0.3"
serde = "1.0.163"
diff --git a/examples/use_websocket/Cargo.toml b/examples/use_websocket/Cargo.toml
index 2f1f0a5..76baa77 100644
--- a/examples/use_websocket/Cargo.toml
+++ b/examples/use_websocket/Cargo.toml
@@ -8,7 +8,8 @@ leptos = { version = "0.6", features = ["nightly", "csr"] }
console_error_panic_hook = "0.1"
console_log = "1"
log = "0.4"
-leptos-use = { path = "../..", features = ["docs"] }
+leptos-use = { path = "../..", features = ["docs", "msgpack_serde"] }
+serde = { version = "1", features = ["derive"] }
web-sys = "0.3"
[dev-dependencies]
diff --git a/examples/use_websocket/src/main.rs b/examples/use_websocket/src/main.rs
index d7fef69..7a5e370 100644
--- a/examples/use_websocket/src/main.rs
+++ b/examples/use_websocket/src/main.rs
@@ -1,12 +1,20 @@
use leptos::*;
use leptos_use::docs::demo_or_body;
use leptos_use::{
- core::ConnectionReadyState, use_websocket, use_websocket_with_options, UseWebSocketOptions,
- UseWebsocketReturn,
+ core::ConnectionReadyState, use_websocket, use_websocket_with_options, UseWebSocketError,
+ UseWebSocketOptions, UseWebSocketReturn,
};
+use serde::{Deserialize, Serialize};
+use leptos_use::utils::{FromToStringCodec, MsgpackSerdeCodec};
use web_sys::{CloseEvent, Event};
+#[derive(Serialize, Deserialize, Debug)]
+struct Apple {
+ name: String,
+ worm_count: u32,
+}
+
#[component]
fn Demo() -> impl IntoView {
let (history, set_history) = create_signal(vec![]);
@@ -18,27 +26,22 @@ fn Demo() -> impl IntoView {
// use_websocket
// ----------------------------
- let UseWebsocketReturn {
+ let UseWebSocketReturn {
ready_state,
message,
- message_bytes,
send,
- send_bytes,
open,
close,
..
- } = use_websocket("wss://echo.websocket.events/");
+ } = use_websocket::("wss://echo.websocket.events/");
let send_message = move |_| {
- let m = "Hello, world!";
- send(m);
- set_history.update(|history: &mut Vec<_>| history.push(format! {"[send]: {:?}", m}));
- };
-
- let send_byte_message = move |_| {
- let m = b"Hello, world!\r\n".to_vec();
- send_bytes(m.clone());
- set_history.update(|history: &mut Vec<_>| history.push(format! {"[send_bytes]: {:?}", m}));
+ let m = Apple {
+ name: "More worm than apple".to_string(),
+ worm_count: 10,
+ };
+ send(&m);
+ set_history.update(|history: &mut Vec<_>| history.push(format!("[send]: {:?}", m)));
};
let status = move || ready_state().to_string();
@@ -53,15 +56,11 @@ fn Demo() -> impl IntoView {
};
create_effect(move |_| {
- if let Some(m) = message.get() {
- update_history(&set_history, format! {"[message]: {:?}", m});
- };
- });
-
- create_effect(move |_| {
- if let Some(m) = message_bytes.get() {
- update_history(&set_history, format! {"[message_bytes]: {:?}", m});
- };
+ message.with(move |message| {
+ if let Some(m) = message {
+ update_history(&set_history, format!("[message]: {:?}", m));
+ }
+ })
});
// ----------------------------
@@ -72,49 +71,44 @@ fn Demo() -> impl IntoView {
let on_open_callback = move |e: Event| {
set_history2.update(|history: &mut Vec<_>| {
- history.push(format! {"[onopen]: event {:?}", e.type_()})
+ history.push(format!("[onopen]: event {:?}", e.type_()))
});
};
let on_close_callback = move |e: CloseEvent| {
set_history2.update(|history: &mut Vec<_>| {
- history.push(format! {"[onclose]: event {:?}", e.type_()})
+ history.push(format!("[onclose]: event {:?}", e.type_()))
});
};
- let on_error_callback = move |e: Event| {
+ let on_error_callback = move |e: UseWebSocketError<_, _>| {
set_history2.update(|history: &mut Vec<_>| {
- history.push(format! {"[onerror]: event {:?}", e.type_()})
+ history.push(match e {
+ UseWebSocketError::Event(e) => format!("[onerror]: event {:?}", e.type_()),
+ _ => format!("[onerror]: {:?}", e),
+ })
});
};
- let on_message_callback = move |m: String| {
- set_history2.update(|history: &mut Vec<_>| history.push(format! {"[onmessage]: {:?}", m}));
+ let on_message_callback = move |m: &String| {
+ set_history2.update(|history: &mut Vec<_>| history.push(format!("[onmessage]: {:?}", m)));
};
- let on_message_bytes_callback = move |m: Vec| {
- set_history2
- .update(|history: &mut Vec<_>| history.push(format! {"[onmessage_bytes]: {:?}", m}));
- };
-
- let UseWebsocketReturn {
+ let UseWebSocketReturn {
ready_state: ready_state2,
send: send2,
- send_bytes: send_bytes2,
open: open2,
close: close2,
message: message2,
- message_bytes: message_bytes2,
..
- } = use_websocket_with_options(
+ } = use_websocket_with_options::(
"wss://echo.websocket.events/",
UseWebSocketOptions::default()
.immediate(false)
.on_open(on_open_callback.clone())
.on_close(on_close_callback.clone())
.on_error(on_error_callback.clone())
- .on_message(on_message_callback.clone())
- .on_message_bytes(on_message_bytes_callback.clone()),
+ .on_message(on_message_callback.clone()),
);
let open_connection2 = move |_| {
@@ -125,28 +119,16 @@ fn Demo() -> impl IntoView {
};
let send_message2 = move |_| {
- let message = "Hello, use_leptos!";
- send2(message);
- update_history(&set_history2, format! {"[send]: {:?}", message});
- };
-
- let send_byte_message2 = move |_| {
- let m = b"Hello, world!\r\n".to_vec();
- send_bytes2(m.clone());
- update_history(&set_history2, format! {"[send_bytes]: {:?}", m});
+ let message = "Hello, use_leptos!".to_string();
+ send2(&message);
+ update_history(&set_history2, format!("[send]: {:?}", message));
};
let status2 = move || ready_state2.get().to_string();
create_effect(move |_| {
if let Some(m) = message2.get() {
- update_history(&set_history2, format! {"[message]: {:?}", m});
- };
- });
-
- create_effect(move |_| {
- if let Some(m) = message_bytes2.get() {
- update_history(&set_history2, format! {"[message_bytes]: {:?}", m});
+ update_history(&set_history2, format!("[message]: {:?}", m));
};
});
@@ -161,9 +143,7 @@ fn Demo() -> impl IntoView {
-
+
@@ -200,9 +180,7 @@ fn Demo() -> impl IntoView {
-
+
"History"
/// }
/// # }
/// ```
///
+/// Here is another example using `msgpack` for encoding and decoding. This means that only binary
+/// messages can be sent or received. For this to work you have to enable the **`msgpack_serde` feature** flag.
+///
+/// ```
+/// # use leptos::*;
+/// # use leptos_use::utils::MsgpackSerdeCodec;
+/// # use leptos_use::{use_websocket, UseWebSocketReturn};
+/// # use serde::{Deserialize, Serialize};
+/// #
+/// # #[component]
+/// # fn Demo() -> impl IntoView {
+/// #[derive(Serialize, Deserialize)]
+/// struct SomeData {
+/// name: String,
+/// count: i32,
+/// }
+///
+/// let UseWebSocketReturn {
+/// message,
+/// send,
+/// ..
+/// } = use_websocket::("wss://some.websocket.server/");
+///
+/// let send_data = move || {
+/// send(&SomeData {
+/// name: "John Doe".to_string(),
+/// count: 42,
+/// });
+/// };
+/// #
+/// # view! {}
+/// }
+/// ```
+///
/// ## Relative Paths
///
/// If the provided `url` is relative, it will be resolved relative to the current page.
@@ -105,11 +141,11 @@ use web_sys::{BinaryType, CloseEvent, Event, MessageEvent, WebSocket};
/// #[derive(Clone)]
/// pub struct WebsocketContext {
/// pub message: Signal