Skip to main content

tako_rs_core/
route.rs

1//! HTTP route definition and path matching functionality.
2//!
3//! This module provides the core `Route` struct for defining HTTP routes with path patterns,
4//! parameter extraction, and middleware support. Routes can contain dynamic segments like
5//! `{id}` that are captured as parameters, and support method-specific handlers with
6//! optional trailing slash redirection and route-specific middleware chains.
7//!
8//! # Examples
9//!
10//! ```rust,no_run
11//! use tako::{router::Router, types::Request};
12//! use http::Method;
13//!
14//! async fn user_handler(_req: Request) -> &'static str {
15//!   "user profile"
16//! }
17//!
18//! // `Route` is constructed indirectly through the router. The route's
19//! // middleware / plugin / timeout / signal configuration is then chained
20//! // off the returned `&Route` reference. Path matching happens inside the
21//! // router and is not exposed on `Route` directly.
22//! let mut router = Router::new();
23//! router
24//!   .route(Method::GET, "/users/{id}", user_handler)
25//!   .timeout(std::time::Duration::from_secs(5));
26//! ```
27
28use std::sync::Arc;
29use std::sync::OnceLock;
30use std::sync::atomic::AtomicBool;
31use std::sync::atomic::Ordering;
32use std::time::Duration;
33
34use arc_swap::ArcSwap;
35use http::Method;
36#[cfg(any(feature = "plugins", feature = "utoipa", feature = "vespera"))]
37use parking_lot::RwLock;
38
39use crate::extractors::json::SimdJsonMode;
40use crate::handler::BoxHandler;
41use crate::middleware::Next;
42#[cfg(any(feature = "utoipa", feature = "vespera"))]
43use crate::openapi::RouteOpenApi;
44#[cfg(feature = "plugins")]
45use crate::plugins::TakoPlugin;
46use crate::responder::Responder;
47#[cfg(feature = "signals")]
48use crate::signals::Signal;
49#[cfg(feature = "signals")]
50use crate::signals::SignalArbiter;
51use crate::types::BoxMiddleware;
52use crate::types::Request;
53
54/// HTTP route with path pattern matching and middleware support.
55#[doc(alias = "route")]
56pub struct Route {
57  /// Original path string used to create this route.
58  pub path: String,
59  /// HTTP method this route responds to.
60  pub method: Method,
61  /// Handler function to execute when route is matched.
62  ///
63  /// Crate-private — `BoxHandler` is itself crate-private and external users
64  /// only see `Route` behind `Arc<Route>` via [`Router::routes`], which makes
65  /// the field unusable from downstream code regardless of visibility. Kept
66  /// crate-visible so the dispatch path in `router.rs` can clone/call it.
67  pub(crate) handler: BoxHandler,
68  /// Route-specific middleware chain.
69  ///
70  /// Crate-private to protect the `has_middleware` shortcut: every mutation
71  /// must go through [`Route::middleware`] so the atomic flag stays in sync
72  /// with the `ArcSwap` contents. Direct `ArcSwap::store` from outside would
73  /// silently desynchronize the hot-path skip in the router.
74  pub(crate) middlewares: ArcSwap<Vec<BoxMiddleware>>,
75  /// Fast check: true when route middleware is registered (avoids `ArcSwap` load on hot path).
76  pub(crate) has_middleware: AtomicBool,
77  /// Whether trailing slash redirection is enabled.
78  pub tsr: bool,
79  /// Route-specific plugins.
80  #[cfg(feature = "plugins")]
81  pub(crate) plugins: RwLock<Vec<Box<dyn TakoPlugin>>>,
82  /// Flag to ensure route plugins are initialized only once.
83  #[cfg(feature = "plugins")]
84  plugins_initialized: AtomicBool,
85  /// HTTP protocol version guard (set once via [`Route::version`] / `h09`/`h10`/`h11`/`h2`).
86  http_protocol: OnceLock<http::Version>,
87  /// Route-level signal arbiter.
88  #[cfg(feature = "signals")]
89  pub(crate) signals: SignalArbiter,
90  /// `OpenAPI` metadata for this route.
91  #[cfg(any(feature = "utoipa", feature = "vespera"))]
92  pub(crate) openapi: RwLock<Option<RouteOpenApi>>,
93  /// Route-specific timeout override (set once at registration, lock-free reads).
94  pub(crate) timeout: OnceLock<Duration>,
95  /// Route-level SIMD JSON dispatch mode (set once at registration, lock-free reads).
96  pub(crate) simd_json_mode: OnceLock<SimdJsonMode>,
97}
98
99impl Route {
100  /// Creates a new route with the specified path, method, and handler.
101  pub fn new(path: String, method: Method, handler: BoxHandler, tsr: Option<bool>) -> Self {
102    Self {
103      path,
104      method,
105      handler,
106      middlewares: ArcSwap::new(Arc::default()),
107      has_middleware: AtomicBool::new(false),
108      tsr: tsr.unwrap_or(false),
109      #[cfg(feature = "plugins")]
110      plugins: RwLock::new(Vec::new()),
111      #[cfg(feature = "plugins")]
112      plugins_initialized: AtomicBool::new(false),
113      http_protocol: OnceLock::new(),
114      #[cfg(feature = "signals")]
115      signals: SignalArbiter::new(),
116      #[cfg(any(feature = "utoipa", feature = "vespera"))]
117      openapi: RwLock::new(None),
118      timeout: OnceLock::new(),
119      simd_json_mode: OnceLock::new(),
120    }
121  }
122
123  /// Adds middleware to this route's execution chain.
124  pub fn middleware<F, Fut, R>(&self, f: F) -> &Self
125  where
126    F: Fn(Request, Next) -> Fut + Clone + Send + Sync + 'static,
127    Fut: std::future::Future<Output = R> + Send + 'static,
128    R: Responder + Send + 'static,
129  {
130    let mw: BoxMiddleware = Arc::new(move |req, next| {
131      let fut = f(req, next); // Fut<'a>
132
133      Box::pin(async move { fut.await.into_response() })
134    });
135
136    // RCU-style append: ArcSwap retries the closure on CAS conflict, so
137    // concurrent route-level middleware pushes cannot lose entries.
138    self.middlewares.rcu(move |current| {
139      let mut next = Vec::with_capacity(current.len() + 1);
140      next.extend(current.iter().cloned());
141      next.push(mw.clone());
142      Arc::new(next)
143    });
144    self.has_middleware.store(true, Ordering::Release);
145    self
146  }
147
148  /// Adds a plugin to this route.
149  ///
150  /// Route-level plugins allow applying functionality like compression, CORS,
151  /// or rate limiting to specific routes instead of globally. Plugins added
152  /// to a route are initialized when the route is first accessed.
153  ///
154  /// # Examples
155  ///
156  /// ```rust
157  /// # #[cfg(feature = "plugins")]
158  /// use tako::{router::Router, Method, responder::Responder, types::Request};
159  /// # #[cfg(feature = "plugins")]
160  /// use tako::plugins::cors::CorsBuilder;
161  ///
162  /// # #[cfg(feature = "plugins")]
163  /// # async fn handler(_req: Request) -> impl Responder {
164  /// #     "Hello, World!"
165  /// # }
166  ///
167  /// # #[cfg(feature = "plugins")]
168  /// # fn example() {
169  /// let mut router = Router::new();
170  /// let route = router.route(Method::GET, "/api/data", handler);
171  ///
172  /// // Apply CORS only to this route
173  /// let cors = CorsBuilder::new()
174  ///     .allow_origin("https://example.com")
175  ///     .build();
176  /// route.plugin(cors);
177  /// # }
178  /// ```
179  #[cfg(feature = "plugins")]
180  #[cfg_attr(docsrs, doc(cfg(feature = "plugins")))]
181  pub fn plugin<P>(&self, plugin: P) -> &Self
182  where
183    P: TakoPlugin + Clone + Send + Sync + 'static,
184  {
185    self.plugins.write().push(Box::new(plugin));
186    self
187  }
188
189  /// Initializes route-level plugins exactly once.
190  ///
191  /// This method sets up all plugins registered with this route by calling
192  /// their setup method. It uses a mini-router to collect the middleware
193  /// that plugins register, then adds that middleware to the route's
194  /// middleware chain. This ensures plugins are only initialized once.
195  #[cfg(feature = "plugins")]
196  #[cfg_attr(docsrs, doc(cfg(feature = "plugins")))]
197  pub(crate) fn setup_plugins_once(&self) {
198    // Hot path: dispatch calls this on every matched route. After the
199    // first request the plugins are installed, so do a cheap Acquire
200    // load and bail before paying for a SeqCst RMW + fence each time.
201    // `Acquire` pairs with the `Release` half of the `swap` below so we
202    // observe the middleware writes published by the initializing thread.
203    if self.plugins_initialized.load(Ordering::Acquire) {
204      return;
205    }
206
207    if !self.plugins_initialized.swap(true, Ordering::SeqCst) {
208      // Create a temporary mini-router to capture plugin middleware
209      let mini_router = crate::router::Router::new();
210
211      let plugins = self.plugins.read();
212      for plugin in plugins.iter() {
213        // See `Router::setup_plugins_once`: log failures so an erroring
214        // route-level plugin (auth, rate-limit, ...) is visible instead
215        // of silently dropped — fail-open without diagnostics is
216        // exactly what the audit calls out.
217        if let Err(e) = plugin.setup(&mini_router) {
218          tracing::error!(
219            plugin = plugin.name(),
220            error = %e,
221            "route-level TakoPlugin::setup failed; plugin not active"
222          );
223        }
224      }
225
226      // Transfer middleware from mini-router to this route
227      let plugin_middlewares = mini_router.middlewares.load();
228      let existing = self.middlewares.load_full();
229      let mut merged = Vec::with_capacity(plugin_middlewares.len() + existing.len());
230      merged.extend(plugin_middlewares.iter().cloned());
231      merged.extend(existing.iter().cloned());
232      if !merged.is_empty() {
233        self.has_middleware.store(true, Ordering::Release);
234      }
235      self.middlewares.store(Arc::new(merged));
236    }
237  }
238
239  /// Restricts this route to a specific HTTP protocol version.
240  ///
241  /// Requests whose `version()` does not match are answered with
242  /// `505 HTTP Version Not Supported`. Set once at registration; later calls
243  /// are no-ops (lock-free reads in the hot path).
244  pub fn version(&self, version: http::Version) -> &Self {
245    if let Err(_existing) = self.http_protocol.set(version) {
246      tracing::warn!(
247        path = %self.path,
248        method = ?self.method,
249        existing = ?self.http_protocol.get().copied(),
250        requested = ?version,
251        "Route::version called twice; subsequent calls are ignored (OnceLock first-wins)",
252      );
253    }
254    self
255  }
256
257  /// HTTP/0.9 guard. Shorthand for [`Route::version`] with [`http::Version::HTTP_09`].
258  pub fn h09(&self) -> &Self {
259    self.version(http::Version::HTTP_09)
260  }
261
262  /// HTTP/1.0 guard. Shorthand for [`Route::version`] with [`http::Version::HTTP_10`].
263  pub fn h10(&self) -> &Self {
264    self.version(http::Version::HTTP_10)
265  }
266
267  /// HTTP/1.1 guard. Shorthand for [`Route::version`] with [`http::Version::HTTP_11`].
268  pub fn h11(&self) -> &Self {
269    self.version(http::Version::HTTP_11)
270  }
271
272  /// HTTP/2 guard. Shorthand for [`Route::version`] with [`http::Version::HTTP_2`].
273  pub fn h2(&self) -> &Self {
274    self.version(http::Version::HTTP_2)
275  }
276
277  /// Returns the configured protocol guard, if any.
278  #[inline]
279  pub(crate) fn protocol_guard(&self) -> Option<http::Version> {
280    self.http_protocol.get().copied()
281  }
282
283  #[cfg(feature = "signals")]
284  /// Returns a reference to this route's signal arbiter.
285  pub fn signals(&self) -> &SignalArbiter {
286    &self.signals
287  }
288
289  #[cfg(feature = "signals")]
290  /// Returns a clone of this route's signal arbiter for shared usage.
291  pub fn signal_arbiter(&self) -> SignalArbiter {
292    self.signals.clone()
293  }
294
295  #[cfg(feature = "signals")]
296  /// Registers a handler for a named signal on this route's arbiter.
297  pub fn on_signal<F, Fut>(&self, id: impl Into<String>, handler: F)
298  where
299    F: Fn(Signal) -> Fut + Send + Sync + 'static,
300    Fut: std::future::Future<Output = ()> + Send + 'static,
301  {
302    self.signals.on(id, handler);
303  }
304
305  #[cfg(feature = "signals")]
306  /// Emits a signal through this route's arbiter.
307  pub async fn emit_signal(&self, signal: Signal) {
308    self.signals.emit(signal).await;
309  }
310
311  // OpenAPI metadata methods
312
313  /// Sets a unique operation ID for this route in `OpenAPI` documentation.
314  ///
315  /// # Examples
316  ///
317  /// ```rust,ignore
318  /// router.route(Method::GET, "/users", list_users)
319  ///     .operation_id("listUsers");
320  /// ```
321  #[cfg(any(feature = "utoipa", feature = "vespera"))]
322  #[cfg_attr(docsrs, doc(cfg(any(feature = "utoipa", feature = "vespera"))))]
323  pub fn operation_id(&self, id: impl Into<String>) -> &Self {
324    let mut guard = self.openapi.write();
325    let openapi = guard.get_or_insert_with(RouteOpenApi::default);
326    openapi.operation_id = Some(id.into());
327    self
328  }
329
330  /// Sets a short summary for this route in `OpenAPI` documentation.
331  ///
332  /// # Examples
333  ///
334  /// ```rust,ignore
335  /// router.route(Method::GET, "/users/{id}", get_user)
336  ///     .summary("Get user by ID");
337  /// ```
338  #[cfg(any(feature = "utoipa", feature = "vespera"))]
339  #[cfg_attr(docsrs, doc(cfg(any(feature = "utoipa", feature = "vespera"))))]
340  pub fn summary(&self, summary: impl Into<String>) -> &Self {
341    let mut guard = self.openapi.write();
342    let openapi = guard.get_or_insert_with(RouteOpenApi::default);
343    openapi.summary = Some(summary.into());
344    self
345  }
346
347  /// Sets a detailed description for this route in `OpenAPI` documentation.
348  ///
349  /// # Examples
350  ///
351  /// ```rust,ignore
352  /// router.route(Method::GET, "/users/{id}", get_user)
353  ///     .description("Retrieves a user by their unique identifier");
354  /// ```
355  #[cfg(any(feature = "utoipa", feature = "vespera"))]
356  #[cfg_attr(docsrs, doc(cfg(any(feature = "utoipa", feature = "vespera"))))]
357  pub fn description(&self, description: impl Into<String>) -> &Self {
358    let mut guard = self.openapi.write();
359    let openapi = guard.get_or_insert_with(RouteOpenApi::default);
360    openapi.description = Some(description.into());
361    self
362  }
363
364  /// Adds a tag to group this route in `OpenAPI` documentation.
365  ///
366  /// # Examples
367  ///
368  /// ```rust,ignore
369  /// router.route(Method::GET, "/users", list_users)
370  ///     .tag("users")
371  ///     .tag("public");
372  /// ```
373  #[cfg(any(feature = "utoipa", feature = "vespera"))]
374  #[cfg_attr(docsrs, doc(cfg(any(feature = "utoipa", feature = "vespera"))))]
375  pub fn tag(&self, tag: impl Into<String>) -> &Self {
376    let mut guard = self.openapi.write();
377    let openapi = guard.get_or_insert_with(RouteOpenApi::default);
378    openapi.tags.push(tag.into());
379    self
380  }
381
382  /// Marks this route as deprecated in `OpenAPI` documentation.
383  ///
384  /// # Examples
385  ///
386  /// ```rust,ignore
387  /// router.route(Method::GET, "/v1/users", list_users_v1)
388  ///     .deprecated();
389  /// ```
390  #[cfg(any(feature = "utoipa", feature = "vespera"))]
391  #[cfg_attr(docsrs, doc(cfg(any(feature = "utoipa", feature = "vespera"))))]
392  pub fn deprecated(&self) -> &Self {
393    let mut guard = self.openapi.write();
394    let openapi = guard.get_or_insert_with(RouteOpenApi::default);
395    openapi.deprecated = true;
396    self
397  }
398
399  /// Adds a response description for a status code in `OpenAPI` documentation.
400  ///
401  /// # Examples
402  ///
403  /// ```rust,ignore
404  /// router.route(Method::GET, "/users/{id}", get_user)
405  ///     .response(200, "Successful response with user data")
406  ///     .response(404, "User not found");
407  /// ```
408  #[cfg(any(feature = "utoipa", feature = "vespera"))]
409  #[cfg_attr(docsrs, doc(cfg(any(feature = "utoipa", feature = "vespera"))))]
410  pub fn response(&self, status: u16, description: impl Into<String>) -> &Self {
411    let mut guard = self.openapi.write();
412    let openapi = guard.get_or_insert_with(RouteOpenApi::default);
413    openapi.responses.insert(status, description.into());
414    self
415  }
416
417  /// Adds a parameter definition for this route in `OpenAPI` documentation.
418  ///
419  /// # Examples
420  ///
421  /// ```rust,ignore
422  /// use tako::openapi::{OpenApiParameter, ParameterLocation};
423  ///
424  /// router.route(Method::GET, "/users", list_users)
425  ///     .parameter(OpenApiParameter {
426  ///         name: "limit".to_string(),
427  ///         location: ParameterLocation::Query,
428  ///         description: Some("Maximum number of results".to_string()),
429  ///         required: false,
430  ///     });
431  /// ```
432  #[cfg(any(feature = "utoipa", feature = "vespera"))]
433  #[cfg_attr(docsrs, doc(cfg(any(feature = "utoipa", feature = "vespera"))))]
434  pub fn parameter(&self, param: crate::openapi::OpenApiParameter) -> &Self {
435    let mut guard = self.openapi.write();
436    let openapi = guard.get_or_insert_with(RouteOpenApi::default);
437    openapi.parameters.push(param);
438    self
439  }
440
441  /// Sets the request body description for this route in `OpenAPI` documentation.
442  ///
443  /// # Examples
444  ///
445  /// ```rust,ignore
446  /// use tako::openapi::OpenApiRequestBody;
447  ///
448  /// router.route(Method::POST, "/users", create_user)
449  ///     .request_body(OpenApiRequestBody {
450  ///         description: Some("User data to create".to_string()),
451  ///         required: true,
452  ///         content_type: "application/json".to_string(),
453  ///     });
454  /// ```
455  #[cfg(any(feature = "utoipa", feature = "vespera"))]
456  #[cfg_attr(docsrs, doc(cfg(any(feature = "utoipa", feature = "vespera"))))]
457  pub fn request_body(&self, body: crate::openapi::OpenApiRequestBody) -> &Self {
458    let mut guard = self.openapi.write();
459    let openapi = guard.get_or_insert_with(RouteOpenApi::default);
460    openapi.request_body = Some(body);
461    self
462  }
463
464  /// Adds a security requirement for this route in `OpenAPI` documentation.
465  ///
466  /// # Examples
467  ///
468  /// ```rust,ignore
469  /// router.route(Method::DELETE, "/users/{id}", delete_user)
470  ///     .security("bearerAuth");
471  /// ```
472  #[cfg(any(feature = "utoipa", feature = "vespera"))]
473  #[cfg_attr(docsrs, doc(cfg(any(feature = "utoipa", feature = "vespera"))))]
474  pub fn security(&self, requirement: impl Into<String>) -> &Self {
475    let mut guard = self.openapi.write();
476    let openapi = guard.get_or_insert_with(RouteOpenApi::default);
477    openapi.security.push(requirement.into());
478    self
479  }
480
481  /// Returns a clone of the `OpenAPI` metadata for this route, if any.
482  #[cfg(any(feature = "utoipa", feature = "vespera"))]
483  #[cfg_attr(docsrs, doc(cfg(any(feature = "utoipa", feature = "vespera"))))]
484  pub fn openapi_metadata(&self) -> Option<RouteOpenApi> {
485    self.openapi.read().clone()
486  }
487
488  /// Sets a timeout for this route, overriding the router-level timeout.
489  ///
490  /// When a request exceeds the timeout duration, the timeout fallback handler
491  /// is invoked (if configured on the router) or a 408 Request Timeout response
492  /// is returned.
493  ///
494  /// # Examples
495  ///
496  /// ```rust,ignore
497  /// use std::time::Duration;
498  ///
499  /// router.route(Method::POST, "/upload", upload_handler)
500  ///     .timeout(Duration::from_secs(60));
501  /// ```
502  pub fn timeout(&self, duration: Duration) -> &Self {
503    if let Err(_existing) = self.timeout.set(duration) {
504      tracing::warn!(
505        path = %self.path,
506        method = ?self.method,
507        existing_ms = self.timeout.get().copied().unwrap_or_default().as_millis() as u64,
508        requested_ms = duration.as_millis() as u64,
509        "Route::timeout called twice; subsequent calls are ignored (OnceLock first-wins)",
510      );
511    }
512    self
513  }
514
515  /// Returns the configured timeout for this route, if any.
516  #[inline]
517  pub(crate) fn get_timeout(&self) -> Option<Duration> {
518    self.timeout.get().copied()
519  }
520
521  /// Configures the SIMD JSON dispatch behavior for this route.
522  ///
523  /// When the `simd` feature is enabled, `Json<T>` can use the `sonic_rs` SIMD
524  /// parser for faster deserialization. By default, SIMD is used for payloads
525  /// above 2 MB. This method lets you override that threshold — or force
526  /// SIMD on/off — for individual routes.
527  ///
528  /// Without the `simd` feature this setting is accepted but has no effect.
529  ///
530  /// # Examples
531  ///
532  /// ```rust,ignore
533  /// use tako::extractors::json::SimdJsonMode;
534  ///
535  /// // Always use SIMD for a heavy ingest endpoint
536  /// router.route(Method::POST, "/api/ingest", ingest)
537  ///     .simd_json(SimdJsonMode::Always);
538  ///
539  /// // Use SIMD only above 4 KB
540  /// router.route(Method::POST, "/api/batch", batch)
541  ///     .simd_json(SimdJsonMode::Threshold(4096));
542  ///
543  /// // Disable SIMD for a latency-sensitive tiny-payload route
544  /// router.route(Method::POST, "/api/ping", ping)
545  ///     .simd_json(SimdJsonMode::Never);
546  /// ```
547  pub fn simd_json(&self, mode: SimdJsonMode) -> &Self {
548    if let Err(_existing) = self.simd_json_mode.set(mode) {
549      tracing::warn!(
550        path = %self.path,
551        method = ?self.method,
552        existing = ?self.simd_json_mode.get().copied(),
553        requested = ?mode,
554        "Route::simd_json called twice; subsequent calls are ignored (OnceLock first-wins)",
555      );
556    }
557    self
558  }
559
560  /// Returns the configured SIMD JSON mode for this route, if any.
561  #[inline]
562  pub(crate) fn get_simd_json_mode(&self) -> Option<SimdJsonMode> {
563    self.simd_json_mode.get().copied()
564  }
565
566  /// Builds a new `Arc<Route>` with the same handler / middlewares / config
567  /// but a different path. Used by [`crate::router::Router::nest`] to register
568  /// a child router's routes under a prefix without mutating the originals.
569  ///
570  /// Route-level plugins are *not* carried over — `TakoPlugin` is not `Clone`,
571  /// and the cloned route is treated as already-initialized so the empty
572  /// plugin list is never set up. Plugin-bearing routes should be registered
573  /// directly on the parent router after `nest`.
574  pub(crate) fn cloned_with_path(&self, new_path: String) -> Arc<Route> {
575    let cloned = Self {
576      path: new_path,
577      method: self.method.clone(),
578      handler: self.handler.clone(),
579      middlewares: ArcSwap::new(self.middlewares.load_full()),
580      has_middleware: AtomicBool::new(self.has_middleware.load(Ordering::Acquire)),
581      tsr: self.tsr,
582      #[cfg(feature = "plugins")]
583      plugins: RwLock::new(Vec::new()),
584      #[cfg(feature = "plugins")]
585      plugins_initialized: AtomicBool::new(true),
586      http_protocol: {
587        let lock = OnceLock::new();
588        if let Some(v) = self.http_protocol.get() {
589          let _ = lock.set(*v);
590        }
591        lock
592      },
593      // Preserve the source route's signal handlers across `cloned_with_path`
594      // (nest/mount): allocating a fresh `SignalArbiter` here used to silently
595      // drop every handler the caller had registered on the original route.
596      #[cfg(feature = "signals")]
597      signals: self.signals.clone(),
598      #[cfg(any(feature = "utoipa", feature = "vespera"))]
599      openapi: RwLock::new(self.openapi.read().clone()),
600      timeout: {
601        let lock = OnceLock::new();
602        if let Some(v) = self.timeout.get() {
603          let _ = lock.set(*v);
604        }
605        lock
606      },
607      simd_json_mode: {
608        let lock = OnceLock::new();
609        if let Some(v) = self.simd_json_mode.get() {
610          let _ = lock.set(*v);
611        }
612        lock
613      },
614    };
615    Arc::new(cloned)
616  }
617}