1010//! ingest side, see [`crate::records`]).
1111
1212use std:: collections:: BTreeMap ;
13+ use std:: sync:: Arc ;
1314
1415use serde:: Serialize ;
1516use serde_json:: Value as JsonValue ;
@@ -54,17 +55,21 @@ pub fn group_sort_key(name: &str) -> (usize, &str) {
5455}
5556
5657/// Body of `GET /api/groups`: every group with its chart links and summary.
58+ ///
59+ /// The inner [`Vec`] is held in an [`Arc`] so [`crate::query_cache::QueryCache`]
60+ /// can serve the same allocation to every concurrent reader without cloning.
61+ /// `Arc<T>` serialises through to `T`, so the wire shape is unchanged.
5762#[ derive( Debug , Serialize ) ]
5863pub struct GroupsResponse {
5964 /// Every group surfaced by the discovery passes, in canonical order.
60- pub groups : Vec < Group > ,
65+ pub groups : Arc < Vec < Group > > ,
6166}
6267
6368/// One group: a display name, a slug for the group permalink, and the chart
6469/// links inside it. Optionally carries a v2-compatible rollup summary and a
6570/// short editorial description (rendered as a hover tooltip on the
6671/// disclosure title).
67- #[ derive( Debug , Serialize ) ]
72+ #[ derive( Debug , Clone , Serialize ) ]
6873pub struct Group {
6974 /// Human-readable group label rendered in the disclosure header.
7075 pub name : String ,
@@ -98,7 +103,7 @@ pub struct GroupChartsResponse {
98103}
99104
100105/// Server-computed group summary, matching the v2 metadata contract.
101- #[ derive( Debug , Serialize ) ]
106+ #[ derive( Debug , Clone , Serialize ) ]
102107#[ serde( tag = "type" ) ]
103108pub enum Summary {
104109 /// Random-access format ranking for the latest populated random-access chart.
@@ -161,7 +166,7 @@ pub enum Summary {
161166}
162167
163168/// One random-access summary row.
164- #[ derive( Debug , Serialize ) ]
169+ #[ derive( Debug , Clone , Serialize ) ]
165170pub struct RandomAccessRanking {
166171 /// Series name, normally the physical format.
167172 pub name : String ,
@@ -172,7 +177,7 @@ pub struct RandomAccessRanking {
172177}
173178
174179/// One query benchmark summary row.
175- #[ derive( Debug , Serialize ) ]
180+ #[ derive( Debug , Clone , Serialize ) ]
176181pub struct QueryRanking {
177182 /// Series name, normally `engine:format`.
178183 pub name : String ,
@@ -186,6 +191,10 @@ pub struct QueryRanking {
186191/// A single chart inside a [`GroupChartsResponse`]. `name` is the chart's
187192/// short label inside the group (e.g. `Q1`); `slug` round-trips through
188193/// `/api/chart/{slug}`.
194+ ///
195+ /// `chart` is held in an [`Arc`] so the cache and the landing-page builder
196+ /// share the same allocation; `Arc<T>` serialises as `T`, so the wire shape
197+ /// is identical to a plain `ChartResponse`.
189198#[ derive( Debug , Serialize ) ]
190199pub struct NamedChartResponse {
191200 /// Chart label rendered in the chart-card title (e.g. `Q1`).
@@ -194,12 +203,12 @@ pub struct NamedChartResponse {
194203 pub slug : String ,
195204 /// Inlined chart payload — same shape as `/api/chart/{slug}`.
196205 #[ serde( flatten) ]
197- pub chart : ChartResponse ,
206+ pub chart : Arc < ChartResponse > ,
198207}
199208
200209/// One chart's short label inside a group (e.g. `Q1`) plus the slug that
201210/// resolves to its `/api/chart/{slug}` payload.
202- #[ derive( Debug , Serialize ) ]
211+ #[ derive( Debug , Clone , Serialize ) ]
203212pub struct ChartLink {
204213 /// Chart label rendered in the chart-card title (e.g. `Q1`).
205214 pub name : String ,
0 commit comments