1- use super :: { Format , TransformEdge } ;
1+ use super :: { Format , InputKind , TransformEdge } ;
22
33/// A pluggable definition of a format-to-format transformation.
44///
@@ -12,15 +12,19 @@ use super::{Format, TransformEdge};
1212/// `"pandoc"` or `"wkhtmltopdf"`), which helps with diagnostics and lets
1313/// callers register multiple competing definitions for the same format pair.
1414///
15+ /// The `input_kind` field controls whether the definition expects a single
16+ /// source document or a collection of source documents as input.
17+ ///
1518/// # Example
1619///
1720/// ```rust
18- /// use renderflow::graph::{Format, TransformDefinition};
21+ /// use renderflow::graph::{Format, InputKind, TransformDefinition};
1922///
2023/// let def = TransformDefinition::new(Format::Markdown, Format::Html, 0.5, 1.0, "pandoc");
2124/// assert_eq!(def.from, Format::Markdown);
2225/// assert_eq!(def.to, Format::Html);
2326/// assert_eq!(def.label, "pandoc");
27+ /// assert_eq!(def.input_kind, InputKind::Single);
2428/// ```
2529#[ derive( Debug , Clone , PartialEq ) ]
2630pub struct TransformDefinition {
@@ -34,10 +38,12 @@ pub struct TransformDefinition {
3438 pub quality : f32 ,
3539 /// Human-readable label identifying the tool or method (e.g. `"pandoc"`).
3640 pub label : String ,
41+ /// Whether this definition consumes a single input or a collection.
42+ pub input_kind : InputKind ,
3743}
3844
3945impl TransformDefinition {
40- /// Create a new `TransformDefinition`.
46+ /// Create a new `TransformDefinition` with [`InputKind::Single`] .
4147 ///
4248 /// # Parameters
4349 ///
@@ -54,13 +60,44 @@ impl TransformDefinition {
5460 cost,
5561 quality : quality. clamp ( 0.0 , 1.0 ) ,
5662 label : label. into ( ) ,
63+ input_kind : InputKind :: Single ,
64+ }
65+ }
66+
67+ /// Create a new `TransformDefinition` with an explicit [`InputKind`].
68+ ///
69+ /// Use this when registering a collection-based transform (e.g. pages → book).
70+ ///
71+ /// # Parameters
72+ ///
73+ /// * `from` – source [`Format`]
74+ /// * `to` – target [`Format`]
75+ /// * `cost` – relative execution cost (lower is cheaper)
76+ /// * `quality` – expected output quality in the range `[0.0, 1.0]`
77+ /// * `label` – human-readable name identifying the conversion tool or method
78+ /// * `input_kind` – whether this definition consumes a single input or a collection
79+ pub fn with_input_kind (
80+ from : Format ,
81+ to : Format ,
82+ cost : f32 ,
83+ quality : f32 ,
84+ label : impl Into < String > ,
85+ input_kind : InputKind ,
86+ ) -> Self {
87+ Self {
88+ from,
89+ to,
90+ cost,
91+ quality : quality. clamp ( 0.0 , 1.0 ) ,
92+ label : label. into ( ) ,
93+ input_kind,
5794 }
5895 }
5996
6097 /// Convert this definition into a [`TransformEdge`] for use in a
6198 /// [`TransformGraph`](super::TransformGraph).
6299 pub fn to_edge ( & self ) -> TransformEdge {
63- TransformEdge :: new ( self . from , self . to , self . cost , self . quality )
100+ TransformEdge :: with_input_kind ( self . from , self . to , self . cost , self . quality , self . input_kind )
64101 }
65102}
66103
@@ -78,6 +115,7 @@ mod tests {
78115 assert_eq ! ( def. cost, 0.5 ) ;
79116 assert ! ( ( def. quality - 1.0 ) . abs( ) < 1e-5 ) ;
80117 assert_eq ! ( def. label, "pandoc" ) ;
118+ assert_eq ! ( def. input_kind, InputKind :: Single ) ;
81119 }
82120
83121 #[ test]
@@ -134,6 +172,32 @@ mod tests {
134172 assert_ne ! ( a, b) ;
135173 }
136174
175+ // ── with_input_kind ───────────────────────────────────────────────────────
176+
177+ #[ test]
178+ fn test_with_input_kind_collection ( ) {
179+ let def = TransformDefinition :: with_input_kind (
180+ Format :: Markdown , Format :: Epub , 1.0 , 0.85 , "book-assembler" , InputKind :: Collection ,
181+ ) ;
182+ assert_eq ! ( def. input_kind, InputKind :: Collection ) ;
183+ assert_eq ! ( def. label, "book-assembler" ) ;
184+ }
185+
186+ #[ test]
187+ fn test_new_defaults_to_single_input_kind ( ) {
188+ let def = TransformDefinition :: new ( Format :: Markdown , Format :: Html , 0.5 , 1.0 , "pandoc" ) ;
189+ assert_eq ! ( def. input_kind, InputKind :: Single ) ;
190+ }
191+
192+ #[ test]
193+ fn test_definition_inequality_by_input_kind ( ) {
194+ let a = TransformDefinition :: new ( Format :: Markdown , Format :: Epub , 1.0 , 0.85 , "tool" ) ;
195+ let b = TransformDefinition :: with_input_kind (
196+ Format :: Markdown , Format :: Epub , 1.0 , 0.85 , "tool" , InputKind :: Collection ,
197+ ) ;
198+ assert_ne ! ( a, b) ;
199+ }
200+
137201 // ── to_edge ───────────────────────────────────────────────────────────────
138202
139203 #[ test]
@@ -153,4 +217,20 @@ mod tests {
153217 let edge = def. to_edge ( ) ;
154218 assert ! ( ( edge. quality - 1.0 ) . abs( ) < 1e-5 ) ;
155219 }
220+
221+ #[ test]
222+ fn test_to_edge_propagates_input_kind_single ( ) {
223+ let def = TransformDefinition :: new ( Format :: Markdown , Format :: Html , 0.5 , 1.0 , "pandoc" ) ;
224+ let edge = def. to_edge ( ) ;
225+ assert_eq ! ( edge. input_kind, InputKind :: Single ) ;
226+ }
227+
228+ #[ test]
229+ fn test_to_edge_propagates_input_kind_collection ( ) {
230+ let def = TransformDefinition :: with_input_kind (
231+ Format :: Markdown , Format :: Epub , 1.0 , 0.85 , "book-assembler" , InputKind :: Collection ,
232+ ) ;
233+ let edge = def. to_edge ( ) ;
234+ assert_eq ! ( edge. input_kind, InputKind :: Collection ) ;
235+ }
156236}
0 commit comments