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}