Преглед изворни кода

Merge branch 'master' into router-typesafe

Evan Almloff пре 2 година
родитељ
комит
495fd22bfd

+ 2 - 9
.github/workflows/macos.yml

@@ -30,14 +30,7 @@ jobs:
     name: Test Suite
     runs-on: macos-latest
     steps:
-      - uses: actions-rs/toolchain@v1
-        with:
-          profile: minimal
-          toolchain: stable
-          override: true
+      - uses: dtolnay/rust-toolchain@stable
       - uses: Swatinem/rust-cache@v2
       - uses: actions/checkout@v3
-      - uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --all --tests
+      - run: cargo test --all --tests

+ 8 - 36
.github/workflows/main.yml

@@ -32,30 +32,19 @@ jobs:
     name: Check
     runs-on: ubuntu-latest
     steps:
-      - uses: actions-rs/toolchain@v1
-        with:
-          profile: minimal
-          toolchain: stable
-          override: true
+      - uses: dtolnay/rust-toolchain@stable
       - uses: Swatinem/rust-cache@v2
       - run: sudo apt-get update
       - run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev
       - uses: actions/checkout@v3
-      - uses: actions-rs/cargo@v1
-        with:
-          command: check
-          args: --all --examples --tests
+      - run: cargo check --all --examples --tests
 
   test:
     if: github.event.pull_request.draft == false
     name: Test Suite
     runs-on: ubuntu-latest
     steps:
-      - uses: actions-rs/toolchain@v1
-        with:
-          profile: minimal
-          toolchain: stable
-          override: true
+      - uses: dtolnay/rust-toolchain@stable
       - uses: Swatinem/rust-cache@v2
       - run: sudo apt-get update
       - run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev
@@ -63,48 +52,31 @@ jobs:
       - uses: browser-actions/setup-firefox@latest
       - uses: jetli/wasm-pack-action@v0.4.0
       - uses: actions/checkout@v3
-      - uses: actions-rs/cargo@v1
-        with:
-          command: make
-          args: tests
+      - run: cargo make tests
 
   fmt:
     if: github.event.pull_request.draft == false
     name: Rustfmt
     runs-on: ubuntu-latest
     steps:
-      - uses: actions-rs/toolchain@v1
-        with:
-          profile: minimal
-          toolchain: stable
-          override: true
+      - uses: dtolnay/rust-toolchain@stable
       - uses: Swatinem/rust-cache@v2
       - run: rustup component add rustfmt
       - uses: actions/checkout@v3
-      - uses: actions-rs/cargo@v1
-        with:
-          command: fmt
-          args: --all -- --check
+      - run: cargo fmt --all -- --check
 
   clippy:
     if: github.event.pull_request.draft == false
     name: Clippy
     runs-on: ubuntu-latest
     steps:
-      - uses: actions-rs/toolchain@v1
-        with:
-          profile: minimal
-          toolchain: stable
-          override: true
+      - uses: dtolnay/rust-toolchain@stable
       - uses: Swatinem/rust-cache@v2
       - run: sudo apt-get update
       - run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev
       - run: rustup component add clippy
       - uses: actions/checkout@v3
-      - uses: actions-rs/cargo@v1
-        with:
-          command: clippy
-          args: --workspace --examples --tests -- -D warnings
+      - run: cargo clippy --workspace --examples --tests -- -D warnings
 
   # Coverage is disabled until we can fix it
   # coverage:

+ 1 - 1
README.md

@@ -64,7 +64,7 @@ fn app(cx: Scope) -> Element {
 }
 ```
 
-Dioxus can be used to deliver webapps, desktop apps, static sites, mobile apps, TUI apps, liveview apps, and more. Dioxus is entirely renderer agnostic and can be used as platform for any renderer.
+Dioxus can be used to deliver webapps, desktop apps, static sites, mobile apps, TUI apps, liveview apps, and more. Dioxus is entirely renderer agnostic and can be used as a platform for any renderer.
 
 If you know React, then you already know Dioxus.
 

+ 0 - 3
docs/guide/examples/server_context.rs

@@ -16,9 +16,6 @@ fn main() {
         use axum::extract::State;
         use axum::routing::get;
 
-        // Register the server function before starting the server
-        DoubleServer::register().unwrap();
-
         tokio::runtime::Runtime::new()
             .unwrap()
             .block_on(async move {

+ 0 - 3
docs/guide/examples/server_context_state.rs

@@ -25,9 +25,6 @@ fn main() {
         use axum::routing::get;
         use std::sync::Arc;
 
-        // Register the server function before starting the server
-        DoubleServer::register().unwrap();
-
         tokio::runtime::Runtime::new()
             .unwrap()
             .block_on(async move {

+ 0 - 3
docs/guide/examples/server_function.rs

@@ -16,9 +16,6 @@ fn main() {
         use axum::extract::State;
         use axum::routing::get;
 
-        // Register the server function before starting the server
-        DoubleServer::register().unwrap();
-
         tokio::runtime::Runtime::new()
             .unwrap()
             .block_on(async move {

+ 1 - 1
docs/guide/src/en/interactivity/event_handlers.md

@@ -29,7 +29,7 @@ To learn what the different event types for HTML provide, read the [events modul
 
 Some events will trigger first on the element the event originated at upward. For example, a click event on a `button` inside a `div` would first trigger the button's event listener and then the div's event listener.
 
-> For more information about event propigation see [the mdn docs on event bubling](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#event_bubbling)
+> For more information about event propagation see [the mdn docs on event bubbling](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#event_bubbling)
 
 If you want to prevent this behavior, you can call `stop_propagation()` on the event:
 

+ 1 - 1
packages/core/src/virtual_dom.rs

@@ -426,7 +426,7 @@ impl VirtualDom {
                         }
                     }
 
-                    parent_path = dbg!(template.parent).and_then(|id| self.elements.get(id.0));
+                    parent_path = template.parent.and_then(|id| self.elements.get(id.0));
                 } else {
                     break;
                 }

+ 1 - 1
packages/desktop/src/query.rs

@@ -22,7 +22,7 @@ pub(crate) struct QueryEngine {
 
 impl Default for QueryEngine {
     fn default() -> Self {
-        let (sender, _) = tokio::sync::broadcast::channel(8);
+        let (sender, _) = tokio::sync::broadcast::channel(1000);
         Self {
             sender: Rc::new(sender),
             active_requests: SharedSlab::default(),

+ 1 - 1
packages/fullstack/Cargo.toml

@@ -13,7 +13,7 @@ keywords = ["dom", "ui", "gui", "react", "ssr", "fullstack"]
 
 [dependencies]
 # server functions
-server_fn = { git = "https://github.com/leptos-rs/leptos", rev = "671b1e4a8fff7a2e05bb621ef08e87be2b18ccae", default-features = false, features = ["stable"] }
+server_fn = { git = "https://github.com/leptos-rs/leptos", rev = "15a4e54435eb5a539afb75891292bcccd2cc8e85", default-features = false, features = ["stable"] }
 dioxus_server_macro = { path = "server-macro" }
 
 # warp

+ 0 - 1
packages/fullstack/README.md

@@ -46,7 +46,6 @@ fn main() {
     );
     #[cfg(feature = "ssr")]
     {
-        GetMeaning::register().unwrap();
         tokio::runtime::Runtime::new()
             .unwrap()
             .block_on(async move {

+ 0 - 3
packages/fullstack/examples/axum-desktop/src/server.rs

@@ -8,9 +8,6 @@ use dioxus_fullstack::prelude::*;
 
 #[tokio::main]
 async fn main() {
-    PostServerData::register().unwrap();
-    GetServerData::register().unwrap();
-
     let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
     axum::Server::bind(&addr)
         .serve(

+ 0 - 2
packages/fullstack/examples/axum-hello-world/src/main.rs

@@ -32,8 +32,6 @@ fn main() {
             true
         }));
 
-        PostServerData::register().unwrap();
-        GetServerData::register().unwrap();
         tokio::runtime::Runtime::new()
             .unwrap()
             .block_on(async move {

+ 0 - 2
packages/fullstack/examples/salvo-hello-world/src/main.rs

@@ -33,8 +33,6 @@ fn main() {
         }));
 
         use salvo::prelude::*;
-        PostServerData::register().unwrap();
-        GetServerData::register().unwrap();
         tokio::runtime::Runtime::new()
             .unwrap()
             .block_on(async move {

+ 0 - 2
packages/fullstack/examples/warp-hello-world/src/main.rs

@@ -32,8 +32,6 @@ fn main() {
             true
         }));
 
-        PostServerData::register().unwrap();
-        GetServerData::register().unwrap();
         tokio::runtime::Runtime::new()
             .unwrap()
             .block_on(async move {

+ 2 - 2
packages/fullstack/server-macro/Cargo.toml

@@ -7,8 +7,8 @@ edition = "2021"
 
 [dependencies]
 quote = "1.0.26"
-server_fn_macro = { git = "https://github.com/leptos-rs/leptos", rev = "671b1e4a8fff7a2e05bb621ef08e87be2b18ccae", features = ["stable"] }
-syn = { version = "1", features = ["full"] }
+server_fn_macro = { git = "https://github.com/leptos-rs/leptos", rev = "15a4e54435eb5a539afb75891292bcccd2cc8e85", features = ["stable"] }
+syn = { version = "2", features = ["full"] }
 
 [lib]
 proc-macro = true

+ 1 - 1
packages/fullstack/server-macro/src/lib.rs

@@ -35,7 +35,6 @@ use server_fn_macro::*;
 /// ```
 ///
 /// Note the following:
-/// - You must **register** the server function by calling `T::register()` somewhere in your main function.
 /// - **Server functions must be `async`.** Even if the work being done inside the function body
 ///   can run synchronously on the server, from the client’s perspective it involves an asynchronous
 ///   function call.
@@ -62,6 +61,7 @@ pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
     match server_macro_impl(
         args.into(),
         s.into(),
+        syn::parse_quote!(::dioxus_fullstack::prelude::ServerFnTraitObj),
         Some(context),
         Some(syn::parse_quote!(::dioxus_fullstack::prelude::server_fn)),
     ) {

+ 7 - 8
packages/fullstack/src/adapters/axum_adapter.rs

@@ -12,7 +12,6 @@
 //!     dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true));
 //!     #[cfg(feature = "ssr")]
 //!     {
-//!         GetServerData::register().unwrap();
 //!         tokio::runtime::Runtime::new()
 //!             .unwrap()
 //!             .block_on(async move {
@@ -107,7 +106,7 @@ pub trait DioxusRouterExt<S> {
     fn register_server_fns_with_handler<H, T>(
         self,
         server_fn_route: &'static str,
-        handler: impl Fn(ServerFunction) -> H,
+        handler: impl FnMut(server_fn::ServerFnTraitObj<DioxusServerContext>) -> H,
     ) -> Self
     where
         H: Handler<T, S>,
@@ -232,7 +231,7 @@ where
     fn register_server_fns_with_handler<H, T>(
         self,
         server_fn_route: &'static str,
-        mut handler: impl FnMut(ServerFunction) -> H,
+        mut handler: impl FnMut(server_fn::ServerFnTraitObj<DioxusServerContext>) -> H,
     ) -> Self
     where
         H: Handler<T, S, Body>,
@@ -243,7 +242,7 @@ where
         for server_fn_path in DioxusServerFnRegistry::paths_registered() {
             let func = DioxusServerFnRegistry::get(server_fn_path).unwrap();
             let full_route = format!("{server_fn_route}/{server_fn_path}");
-            match func.encoding {
+            match func.encoding() {
                 Encoding::Url | Encoding::Cbor => {
                     router = router.route(&full_route, post(handler(func)));
                 }
@@ -314,7 +313,7 @@ where
         let cfg = cfg.into();
 
         // Add server functions and render index.html
-        self.serve_static_assets(&cfg.assets_path)
+        self.serve_static_assets(cfg.assets_path)
             .route(
                 "/",
                 get(render_handler).with_state((cfg, SSRState::default())),
@@ -371,7 +370,7 @@ async fn render_handler<P: Clone + serde::Serialize + Send + Sync + 'static>(
 /// A default handler for server functions. It will deserialize the request, call the server function, and serialize the response.
 pub async fn server_fn_handler(
     server_context: DioxusServerContext,
-    function: ServerFunction,
+    function: server_fn::ServerFnTraitObj<DioxusServerContext>,
     parts: Arc<RequestParts>,
     body: Body,
 ) -> impl IntoResponse {
@@ -389,11 +388,11 @@ pub async fn server_fn_handler(
                 .expect("couldn't spawn runtime")
                 .block_on(async {
                     let query = &query_string.into();
-                    let data = match &function.encoding {
+                    let data = match &function.encoding() {
                         Encoding::Url | Encoding::Cbor => &body,
                         Encoding::GetJSON | Encoding::GetCBOR => query,
                     };
-                    let resp = match (function.trait_obj)(server_context.clone(), &data).await {
+                    let resp = match function.call(server_context.clone(), data).await {
                         Ok(serialized) => {
                             // if this is Accept: application/json then send a serialized JSON response
                             let accept_header = parts

+ 14 - 12
packages/fullstack/src/adapters/salvo_adapter.rs

@@ -12,7 +12,6 @@
 //!     #[cfg(feature = "ssr")]
 //!     {
 //!         use salvo::prelude::*;
-//!         GetServerData::register().unwrap();
 //!         tokio::runtime::Runtime::new()
 //!             .unwrap()
 //!             .block_on(async move {
@@ -77,7 +76,7 @@ pub trait DioxusRouterExt {
     /// use dioxus_fullstack::prelude::*;
     ///
     /// struct ServerFunctionHandler {
-    ///     server_fn: ServerFunction,
+    ///     server_fn: server_fn::ServerFnTraitObj<DioxusServerContext>,
     /// }
     ///
     /// #[handler]
@@ -110,7 +109,7 @@ pub trait DioxusRouterExt {
     fn register_server_fns_with_handler<H>(
         self,
         server_fn_route: &'static str,
-        handler: impl Fn(ServerFunction) -> H,
+        handler: impl Fn(server_fn::ServerFnTraitObj<DioxusServerContext>) -> H,
     ) -> Self
     where
         H: Handler + 'static;
@@ -204,7 +203,7 @@ impl DioxusRouterExt for Router {
     fn register_server_fns_with_handler<H>(
         self,
         server_fn_route: &'static str,
-        mut handler: impl FnMut(ServerFunction) -> H,
+        mut handler: impl FnMut(server_fn::ServerFnTraitObj<DioxusServerContext>) -> H,
     ) -> Self
     where
         H: Handler + 'static,
@@ -213,7 +212,7 @@ impl DioxusRouterExt for Router {
         for server_fn_path in DioxusServerFnRegistry::paths_registered() {
             let func = DioxusServerFnRegistry::get(server_fn_path).unwrap();
             let full_route = format!("{server_fn_route}/{server_fn_path}");
-            match func.encoding {
+            match func.encoding() {
                 Encoding::Url | Encoding::Cbor => {
                     router = router.push(Router::with_path(&full_route).post(handler(func)));
                 }
@@ -280,7 +279,7 @@ impl DioxusRouterExt for Router {
     ) -> Self {
         let cfg = cfg.into();
 
-        self.serve_static_assets(&cfg.assets_path)
+        self.serve_static_assets(cfg.assets_path)
             .connect_hot_reload()
             .register_server_fns(server_fn_path)
             .push(Router::with_path("/").get(SSRHandler { cfg }))
@@ -288,8 +287,8 @@ impl DioxusRouterExt for Router {
 
     fn connect_hot_reload(self) -> Self {
         let mut _dioxus_router = Router::with_path("_dioxus");
-        _dioxus_router = _dioxus_router
-            .push(Router::with_path("hot_reload").handle(HotReloadHandler::default()));
+        _dioxus_router =
+            _dioxus_router.push(Router::with_path("hot_reload").handle(HotReloadHandler));
         #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))]
         {
             _dioxus_router = _dioxus_router.push(Router::with_path("disconnect").handle(ignore_ws));
@@ -346,12 +345,15 @@ impl<P: Clone + serde::Serialize + Send + Sync + 'static> Handler for SSRHandler
 /// A default handler for server functions. It will deserialize the request body, call the server function, and serialize the response.
 pub struct ServerFnHandler {
     server_context: DioxusServerContext,
-    function: ServerFunction,
+    function: server_fn::ServerFnTraitObj<DioxusServerContext>,
 }
 
 impl ServerFnHandler {
     /// Create a new server function handler with the given server context and server function.
-    pub fn new(server_context: impl Into<DioxusServerContext>, function: ServerFunction) -> Self {
+    pub fn new(
+        server_context: impl Into<DioxusServerContext>,
+        function: server_fn::ServerFnTraitObj<DioxusServerContext>,
+    ) -> Self {
         let server_context = server_context.into();
         Self {
             server_context,
@@ -395,11 +397,11 @@ impl ServerFnHandler {
                 tokio::runtime::Runtime::new()
                     .expect("couldn't spawn runtime")
                     .block_on(async move {
-                        let data = match &function.encoding {
+                        let data = match function.encoding() {
                             Encoding::Url | Encoding::Cbor => &body,
                             Encoding::GetJSON | Encoding::GetCBOR => &query,
                         };
-                        let resp = (function.trait_obj)(server_context, data).await;
+                        let resp = function.call(server_context, data).await;
 
                         resp_tx.send(resp).unwrap();
                     })

+ 8 - 9
packages/fullstack/src/adapters/warp_adapter.rs

@@ -11,7 +11,6 @@
 //!     dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true));
 //!     #[cfg(feature = "ssr")]
 //!     {
-//!         GetServerData::register().unwrap();
 //!         tokio::runtime::Runtime::new()
 //!             .unwrap()
 //!             .block_on(async move {
@@ -93,7 +92,7 @@ pub fn register_server_fns_with_handler<H, F, R>(
     mut handler: H,
 ) -> BoxedFilter<(R,)>
 where
-    H: FnMut(String, ServerFunction) -> F,
+    H: FnMut(String, server_fn::ServerFnTraitObj<DioxusServerContext>) -> F,
     F: Filter<Extract = (R,), Error = warp::Rejection> + Send + Sync + 'static,
     F::Extract: Send,
     R: Reply + 'static,
@@ -104,7 +103,7 @@ where
         let full_route = format!("{server_fn_route}/{server_fn_path}")
             .trim_start_matches('/')
             .to_string();
-        let route = handler(full_route, func.clone()).boxed();
+        let route = handler(full_route, func).boxed();
         if let Some(boxed_filter) = filter.take() {
             filter = Some(boxed_filter.or(route).unify().boxed());
         } else {
@@ -128,7 +127,7 @@ where
 /// ```
 pub fn register_server_fns(server_fn_route: &'static str) -> BoxedFilter<(impl Reply,)> {
     register_server_fns_with_handler(server_fn_route, |full_route, func| {
-        path(full_route.clone())
+        path(full_route)
             .and(warp::post().or(warp::get()).unify())
             .and(request_parts())
             .and(warp::body::bytes())
@@ -250,7 +249,7 @@ impl warp::reject::Reject for RecieveFailed {}
 /// A default handler for server functions. It will deserialize the request body, call the server function, and serialize the response.
 pub async fn server_fn_handler(
     server_context: impl Into<DioxusServerContext>,
-    function: ServerFunction,
+    function: server_fn::ServerFnTraitObj<DioxusServerContext>,
     parts: RequestParts,
     body: Bytes,
 ) -> Result<Box<dyn warp::Reply>, warp::Rejection> {
@@ -274,11 +273,11 @@ pub async fn server_fn_handler(
                         .as_bytes()
                         .to_vec()
                         .into();
-                    let data = match &function.encoding {
+                    let data = match function.encoding() {
                         Encoding::Url | Encoding::Cbor => &body,
                         Encoding::GetJSON | Encoding::GetCBOR => &query,
                     };
-                    let resp = match (function.trait_obj)(server_context.clone(), data).await {
+                    let resp = match function.call(server_context.clone(), data).await {
                         Ok(serialized) => {
                             // if this is Accept: application/json then send a serialized JSON response
                             let accept_header = parts
@@ -373,7 +372,7 @@ pub fn connect_hot_reload() -> impl Filter<Extract = (impl Reply,), Error = warp
         use warp::ws::Message;
 
         let hot_reload = warp::path!("_dioxus" / "hot_reload")
-            .and(warp::any().then(|| crate::hot_reload::spawn_hot_reload()))
+            .and(warp::any().then(crate::hot_reload::spawn_hot_reload))
             .and(warp::ws())
             .map(move |state: &'static HotReloadState, ws: warp::ws::Ws| {
                 #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))]
@@ -425,7 +424,7 @@ pub fn connect_hot_reload() -> impl Filter<Extract = (impl Reply,), Error = warp
                         struct DisconnectOnDrop(Option<warp::ws::WebSocket>);
                         impl Drop for DisconnectOnDrop {
                             fn drop(&mut self) {
-                                let _ = self.0.take().unwrap().close();
+                                std::mem::drop(self.0.take().unwrap().close());
                             }
                         }
 

+ 1 - 1
packages/fullstack/src/lib.rs

@@ -36,7 +36,7 @@ pub mod prelude {
     #[cfg(feature = "ssr")]
     pub use crate::server_context::RequestParts;
     pub use crate::server_context::{DioxusServerContext, HasServerContext};
-    pub use crate::server_fn::ServerFn;
+    pub use crate::server_fn::DioxusServerFn;
     #[cfg(feature = "ssr")]
     pub use crate::server_fn::{ServerFnTraitObj, ServerFunction};
     pub use dioxus_server_macro::*;

+ 71 - 23
packages/fullstack/src/server_fn.rs

@@ -1,18 +1,63 @@
 use crate::server_context::DioxusServerContext;
 
 #[cfg(any(feature = "ssr", doc))]
+#[derive(Clone)]
 /// A trait object for a function that be called on serializable arguments and returns a serializable result.
-pub type ServerFnTraitObj = server_fn::ServerFnTraitObj<DioxusServerContext>;
+pub struct ServerFnTraitObj(server_fn::ServerFnTraitObj<DioxusServerContext>);
+
+#[cfg(any(feature = "ssr", doc))]
+impl std::ops::Deref for ServerFnTraitObj {
+    type Target = server_fn::ServerFnTraitObj<DioxusServerContext>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+#[cfg(any(feature = "ssr", doc))]
+impl std::ops::DerefMut for ServerFnTraitObj {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+#[cfg(any(feature = "ssr", doc))]
+impl ServerFnTraitObj {
+    fn new(
+        prefix: &'static str,
+        url: &'static str,
+        encoding: server_fn::Encoding,
+        run: ServerFunction,
+    ) -> Self {
+        Self(server_fn::ServerFnTraitObj::new(prefix, url, encoding, run))
+    }
+
+    /// Create a new `ServerFnTraitObj` from a `server_fn::ServerFnTraitObj`.
+    pub const fn from_generic_server_fn(
+        server_fn: server_fn::ServerFnTraitObj<DioxusServerContext>,
+    ) -> Self {
+        Self(server_fn)
+    }
+}
+
+#[cfg(any(feature = "ssr", doc))]
+server_fn::inventory::collect!(ServerFnTraitObj);
 
 #[cfg(any(feature = "ssr", doc))]
 /// A server function that can be called on serializable arguments and returns a serializable result.
-pub type ServerFunction = server_fn::ServerFunction<DioxusServerContext>;
+pub type ServerFunction = server_fn::SerializedFnTraitObj<DioxusServerContext>;
 
 #[cfg(any(feature = "ssr", doc))]
 #[allow(clippy::type_complexity)]
 static REGISTERED_SERVER_FUNCTIONS: once_cell::sync::Lazy<
-    std::sync::Arc<std::sync::RwLock<std::collections::HashMap<&'static str, ServerFunction>>>,
-> = once_cell::sync::Lazy::new(Default::default);
+    std::sync::Arc<std::sync::RwLock<std::collections::HashMap<&'static str, ServerFnTraitObj>>>,
+> = once_cell::sync::Lazy::new(|| {
+    let mut map = std::collections::HashMap::new();
+    for server_fn in server_fn::inventory::iter::<ServerFnTraitObj> {
+        map.insert(server_fn.0.url(), server_fn.clone());
+    }
+    std::sync::Arc::new(std::sync::RwLock::new(map))
+});
 
 #[cfg(any(feature = "ssr", doc))]
 /// The registry of all Dioxus server functions.
@@ -22,9 +67,10 @@ pub struct DioxusServerFnRegistry;
 impl server_fn::ServerFunctionRegistry<DioxusServerContext> for DioxusServerFnRegistry {
     type Error = ServerRegistrationFnError;
 
-    fn register(
+    fn register_explicit(
+        prefix: &'static str,
         url: &'static str,
-        server_function: std::sync::Arc<ServerFnTraitObj>,
+        server_function: ServerFunction,
         encoding: server_fn::Encoding,
     ) -> Result<(), Self::Error> {
         // store it in the hashmap
@@ -33,10 +79,7 @@ impl server_fn::ServerFunctionRegistry<DioxusServerContext> for DioxusServerFnRe
             .map_err(|e| ServerRegistrationFnError::Poisoned(e.to_string()))?;
         let prev = write.insert(
             url,
-            ServerFunction {
-                trait_obj: server_function,
-                encoding,
-            },
+            ServerFnTraitObj::new(prefix, url, encoding, server_function),
         );
 
         // if there was already a server function with this key,
@@ -53,27 +96,32 @@ impl server_fn::ServerFunctionRegistry<DioxusServerContext> for DioxusServerFnRe
         }
     }
 
+    fn register(
+        url: &'static str,
+        server_function: ServerFunction,
+        encoding: server_fn::Encoding,
+    ) -> Result<(), Self::Error> {
+        Self::register_explicit("", url, server_function, encoding)
+    }
+
     /// Returns the server function registered at the given URL, or `None` if no function is registered at that URL.
-    fn get(url: &str) -> Option<ServerFunction> {
+    fn get(url: &str) -> Option<server_fn::ServerFnTraitObj<DioxusServerContext>> {
         REGISTERED_SERVER_FUNCTIONS
             .read()
             .ok()
-            .and_then(|fns| fns.get(url).cloned())
+            .and_then(|fns| fns.get(url).map(|inner| inner.0.clone()))
     }
 
     /// Returns the server function registered at the given URL, or `None` if no function is registered at that URL.
-    fn get_trait_obj(url: &str) -> Option<std::sync::Arc<ServerFnTraitObj>> {
-        REGISTERED_SERVER_FUNCTIONS
-            .read()
-            .ok()
-            .and_then(|fns| fns.get(url).map(|f| f.trait_obj.clone()))
+    fn get_trait_obj(url: &str) -> Option<server_fn::ServerFnTraitObj<DioxusServerContext>> {
+        Self::get(url)
     }
 
     fn get_encoding(url: &str) -> Option<server_fn::Encoding> {
         REGISTERED_SERVER_FUNCTIONS
             .read()
             .ok()
-            .and_then(|fns| fns.get(url).map(|f| f.encoding.clone()))
+            .and_then(|fns| fns.get(url).map(|f| f.encoding()))
     }
 
     /// Returns a list of all registered server functions.
@@ -103,16 +151,16 @@ pub enum ServerRegistrationFnError {
 ///
 /// Server functions are created using the `server` macro.
 ///
-/// The function should be registered by calling `ServerFn::register()`. The set of server functions
+/// The set of server functions
 /// can be queried on the server for routing purposes by calling [server_fn::ServerFunctionRegistry::get].
 ///
 /// Technically, the trait is implemented on a type that describes the server function's arguments, not the function itself.
-pub trait ServerFn: server_fn::ServerFn<DioxusServerContext> {
+pub trait DioxusServerFn: server_fn::ServerFn<DioxusServerContext> {
     /// Registers the server function, allowing the client to query it by URL.
     #[cfg(any(feature = "ssr", doc))]
-    fn register() -> Result<(), server_fn::ServerFnError> {
-        Self::register_in::<DioxusServerFnRegistry>()
+    fn register_explicit() -> Result<(), server_fn::ServerFnError> {
+        Self::register_in_explicit::<DioxusServerFnRegistry>()
     }
 }
 
-impl<T> ServerFn for T where T: server_fn::ServerFn<DioxusServerContext> {}
+impl<T> DioxusServerFn for T where T: server_fn::ServerFn<DioxusServerContext> {}

+ 1 - 1
packages/hooks/src/use_shared_state.rs

@@ -71,7 +71,7 @@ impl<T> ProvidedStateInner<T> {
 ///     let current_theme = *theme.read();
 ///
 ///     render! {
-///         match &*theme.read() {
+///         match current_theme {
 ///             Theme::Dark => {
 ///                 "Dark mode"
 ///             }

+ 1 - 1
packages/interpreter/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = "dioxus-interpreter-js"
-version = "0.3.2"
+version = "0.3.3"
 edition = "2018"
 authors = ["Jonathan Kelley"]
 description = "JS Intepreter for Dioxus - a concurrent renderer-agnostic Virtual DOM for interactive user experiences"