switchback_traits/traits/contract.rs
1//! Loaded contract instance view (sync API on an in-memory loaded contract).
2
3use crate::ids::{EntityId, SpecVersion};
4use crate::link_context::LinkContext;
5use crate::options::Options;
6use crate::traits::contract_family::ContractFamily;
7use crate::traits::entity_category::EntityCategory;
8use crate::{Companion, CompanionFile, EntityBody, Group, Span};
9
10/// Parser-side entity with a family-typed category.
11///
12/// In-memory view produced by contract-family parsers. Convert to wire
13/// [`StoredEntity`](crate::StoredEntity) when building a [`ReferenceManual`](crate::ReferenceManual).
14#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct Entity<C: EntityCategory> {
16 /// Entity address within the loaded contract.
17 pub id: EntityId,
18 /// Family-specific typed category marker.
19 pub category: C,
20 /// Human-readable entity title.
21 pub title: String,
22 /// Leading documentation prose, when present.
23 pub doc: Option<String>,
24 /// Source span within the input document, when available.
25 ///
26 /// Parser-local provenance; maps to wire [`Source`](crate::Source) at serialize time.
27 pub source_span: Option<Span>,
28 /// Category-specific entity payload.
29 pub body: EntityBody,
30}
31
32/// A loaded, resolved contract ready to render or serialize.
33///
34/// Parser crates implement this trait after parsing and resolving references.
35/// The sync API supports in-memory traversal during manual assembly.
36pub trait Contract: Send + Sync {
37 /// Contract family metadata and capabilities.
38 type Family: ContractFamily;
39
40 /// Returns the contract family identity for this loaded instance.
41 fn family(&self) -> &Self::Family;
42
43 /// Returns the parsed spec version for this contract instance.
44 fn version(&self) -> &SpecVersion;
45
46 /// Family-specific entity category type.
47 type Category: EntityCategory;
48
49 /// Returns all groups in this contract (entities are queried per group).
50 fn groups(&self) -> &[Group];
51
52 /// Returns entities belonging to `group`.
53 fn entities(&self, group: &Group) -> &[Entity<Self::Category>];
54
55 /// Builds a [`LinkContext`] for cross-reference formatting under `opts`.
56 fn link_context(&self, opts: &Options) -> LinkContext;
57
58 /// Returns optional overview prose for `group`, when the family provides it.
59 fn group_overview(&self, group: &Group) -> Option<&str> {
60 let _ = group;
61 None
62 }
63
64 /// Returns parser-side companion files discovered for this contract.
65 ///
66 /// Default empty; families with companion docs override. Convert to wire
67 /// [`Companion`](crate::Companion) via [`companion_files_to_stored`](crate::traits::companion_files_to_stored).
68 fn companions(&self) -> &[CompanionFile] {
69 &[]
70 }
71}
72
73/// Convert parser-side companions into stored switchback companions.
74///
75/// Strips parser-local fields (e.g. [`CompanionFile::source_path`]) and assigns
76/// a uniform `media_type` for the wire representation.
77pub fn companion_files_to_stored(files: &[CompanionFile], media_type: &str) -> Vec<Companion> {
78 files
79 .iter()
80 .map(|file| Companion {
81 output_name: file.output_name.clone(),
82 bytes: file.bytes.clone(),
83 media_type: media_type.to_string(),
84 title: file.title.clone(),
85 source_dir: file.source_dir.clone(),
86 stem: file.stem.clone(),
87 })
88 .collect()
89}