Skip to main content

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}