1- //! Typed composition of declaration requirements, scalar binding, and syntax checks.
1+ //! Typed composition of declaration requirements, scalar binding, source acquisition,
2+ //! and syntax checks.
23//!
3- //! Requirements and binding fan out from caller-supplied source claims. Source
4- //! bytes remain caller-owned, and successful output is the detached bound
5- //! projection rather than persisted declaration evidence.
4+ //! Requirements and binding fan out from caller-supplied source claims. The
5+ //! in-memory entry point borrows caller-owned bytes; the root entry point reads
6+ //! them through caller-supplied directory capabilities. Successful output is
7+ //! the detached bound projection rather than persisted declaration evidence.
68
79use std:: fmt;
810
911use crate :: bound_scalars:: { BoundScalarError , BoundScalarProjection , bind_scalar_source_claims} ;
1012use crate :: declaration_requirements:: {
11- DeclarationRequirementError , project_declaration_requirements,
13+ DeclarationRequirementError , DeclarationRequirementProjection , project_declaration_requirements,
14+ } ;
15+ use crate :: declaration_source:: {
16+ DeclarationSourceError , DeclarationSourceLimits , DeclarationSourceRoots ,
17+ read_declaration_sources,
1218} ;
1319use crate :: declaration_syntax:: {
1420 DeclarationSourceDocument , DeclarationSyntaxError , DeclarationSyntaxLimits ,
@@ -17,6 +23,43 @@ use crate::declaration_syntax::{
1723use crate :: scalar_names:: NamedScalarProjection ;
1824use crate :: scalar_source_claims:: ScalarSourceClaimProjection ;
1925
26+ /// Inclusive bounds shared by root acquisition and declaration syntax checking.
27+ #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
28+ pub struct DeclarationRootPipelineLimits {
29+ /// Maximum number of unique source documents.
30+ pub max_documents : usize ,
31+ /// Maximum number of owner declaration requirements.
32+ pub max_requirements : usize ,
33+ /// Maximum byte count for one source document.
34+ pub max_source_bytes : usize ,
35+ /// Maximum byte count across all source documents.
36+ pub max_total_source_bytes : usize ,
37+ /// Maximum number of direct members in one parsed owner class.
38+ pub max_direct_members : usize ,
39+ }
40+
41+ impl From < DeclarationRootPipelineLimits > for DeclarationSourceLimits {
42+ fn from ( limits : DeclarationRootPipelineLimits ) -> Self {
43+ Self {
44+ max_documents : limits. max_documents ,
45+ max_source_bytes : limits. max_source_bytes ,
46+ max_total_source_bytes : limits. max_total_source_bytes ,
47+ }
48+ }
49+ }
50+
51+ impl From < DeclarationRootPipelineLimits > for DeclarationSyntaxLimits {
52+ fn from ( limits : DeclarationRootPipelineLimits ) -> Self {
53+ Self {
54+ max_documents : limits. max_documents ,
55+ max_requirements : limits. max_requirements ,
56+ max_source_bytes : limits. max_source_bytes ,
57+ max_total_source_bytes : limits. max_total_source_bytes ,
58+ max_direct_members : limits. max_direct_members ,
59+ }
60+ }
61+ }
62+
2063/// Failure from the first declaration pipeline stage that rejects its input.
2164#[ derive( Clone , Debug , PartialEq , Eq ) ]
2265pub enum DeclarationPipelineError {
@@ -50,6 +93,64 @@ impl std::error::Error for DeclarationPipelineError {
5093 }
5194}
5295
96+ /// Failure from source acquisition or the typed declaration pipeline around it.
97+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
98+ pub enum DeclarationRootPipelineError {
99+ /// Requirements, binding, or syntax checking failed.
100+ Pipeline ( DeclarationPipelineError ) ,
101+ /// Capability-relative source acquisition failed.
102+ Source ( DeclarationSourceError ) ,
103+ }
104+
105+ impl fmt:: Display for DeclarationRootPipelineError {
106+ fn fmt ( & self , formatter : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
107+ match self {
108+ Self :: Pipeline ( error) => write ! ( formatter, "declaration pipeline failed: {error}" ) ,
109+ Self :: Source ( error) => {
110+ write ! ( formatter, "declaration source acquisition failed: {error}" )
111+ }
112+ }
113+ }
114+ }
115+
116+ impl std:: error:: Error for DeclarationRootPipelineError {
117+ fn source ( & self ) -> Option < & ( dyn std:: error:: Error + ' static ) > {
118+ match self {
119+ Self :: Pipeline ( error) => Some ( error) ,
120+ Self :: Source ( error) => Some ( error) ,
121+ }
122+ }
123+ }
124+
125+ struct PreparedDeclarationPipeline {
126+ requirements : DeclarationRequirementProjection ,
127+ bound_projection : BoundScalarProjection ,
128+ }
129+
130+ fn prepare_declaration_pipeline (
131+ named_projection : & NamedScalarProjection ,
132+ source_claim_projection : & ScalarSourceClaimProjection ,
133+ ) -> Result < PreparedDeclarationPipeline , DeclarationPipelineError > {
134+ let requirements = project_declaration_requirements ( source_claim_projection)
135+ . map_err ( DeclarationPipelineError :: Requirements ) ?;
136+ let bound_projection = bind_scalar_source_claims ( named_projection, source_claim_projection)
137+ . map_err ( DeclarationPipelineError :: Binding ) ?;
138+ Ok ( PreparedDeclarationPipeline {
139+ requirements,
140+ bound_projection,
141+ } )
142+ }
143+
144+ fn complete_declaration_pipeline (
145+ prepared : PreparedDeclarationPipeline ,
146+ documents : & [ DeclarationSourceDocument ] ,
147+ limits : DeclarationSyntaxLimits ,
148+ ) -> Result < BoundScalarProjection , DeclarationPipelineError > {
149+ check_owner_declaration_syntax ( & prepared. requirements , documents, limits)
150+ . map_err ( DeclarationPipelineError :: Syntax ) ?;
151+ Ok ( prepared. bound_projection )
152+ }
153+
53154/// Projects requirements, binds scalar claims, and checks supplied source bytes.
54155///
55156/// Requirements are derived directly from `source_claim_projection`; the bound
@@ -65,13 +166,35 @@ pub fn check_declaration_pipeline(
65166 documents : & [ DeclarationSourceDocument ] ,
66167 limits : DeclarationSyntaxLimits ,
67168) -> Result < BoundScalarProjection , DeclarationPipelineError > {
68- let requirements = project_declaration_requirements ( source_claim_projection)
69- . map_err ( DeclarationPipelineError :: Requirements ) ?;
70- let bound_projection = bind_scalar_source_claims ( named_projection, source_claim_projection)
71- . map_err ( DeclarationPipelineError :: Binding ) ?;
72- check_owner_declaration_syntax ( & requirements, documents, limits)
73- . map_err ( DeclarationPipelineError :: Syntax ) ?;
74- Ok ( bound_projection)
169+ let prepared = prepare_declaration_pipeline ( named_projection, source_claim_projection) ?;
170+ complete_declaration_pipeline ( prepared, documents, limits)
171+ }
172+
173+ /// Projects requirements, binds scalar claims, acquires source bytes, and checks syntax.
174+ ///
175+ /// Both directory capabilities remain borrowed. Requirements and binding finish
176+ /// before either root is read; acquisition finishes before syntax checking. The
177+ /// bound projection is returned only after every stage succeeds.
178+ ///
179+ /// # Errors
180+ ///
181+ /// Returns the first failed stage with its unchanged pipeline or source error.
182+ pub fn check_declaration_pipeline_from_roots (
183+ named_projection : & NamedScalarProjection ,
184+ source_claim_projection : & ScalarSourceClaimProjection ,
185+ roots : DeclarationSourceRoots < ' _ > ,
186+ limits : DeclarationRootPipelineLimits ,
187+ ) -> Result < BoundScalarProjection , DeclarationRootPipelineError > {
188+ let prepared = prepare_declaration_pipeline ( named_projection, source_claim_projection)
189+ . map_err ( DeclarationRootPipelineError :: Pipeline ) ?;
190+ let documents = read_declaration_sources (
191+ & prepared. requirements ,
192+ roots,
193+ DeclarationSourceLimits :: from ( limits) ,
194+ )
195+ . map_err ( DeclarationRootPipelineError :: Source ) ?;
196+ complete_declaration_pipeline ( prepared, & documents, DeclarationSyntaxLimits :: from ( limits) )
197+ . map_err ( DeclarationRootPipelineError :: Pipeline )
75198}
76199
77200#[ cfg( test) ]
0 commit comments