1use sklears_core::error::{Result as SklResult, SklearsError};
8use std::collections::HashMap;
9use std::marker::PhantomData;
10use std::time::Instant;
11use thiserror::Error;
12
13use super::component_framework::PluggableComponent;
14use super::pipeline_system::PipelineData;
15
16#[derive(Debug)]
21pub struct TypeSafeComposer<I, O> {
22 stages: Vec<TypedCompositionStage>,
24 type_constraints: TypeConstraints,
26 metadata: CompositionMetadata,
28 _input_type: PhantomData<I>,
30 _output_type: PhantomData<O>,
31}
32
33impl<I, O> Default for TypeSafeComposer<I, O>
34where
35 I: CompositionType + Send + Sync + 'static,
36 O: CompositionType + Send + Sync + 'static,
37{
38 fn default() -> Self {
39 Self::new()
40 }
41}
42
43impl<I, O> TypeSafeComposer<I, O>
44where
45 I: CompositionType + Send + Sync + 'static,
46 O: CompositionType + Send + Sync + 'static,
47{
48 #[must_use]
50 pub fn new() -> Self {
51 Self {
52 stages: Vec::new(),
53 type_constraints: TypeConstraints::new(),
54 metadata: CompositionMetadata::new(),
55 _input_type: PhantomData,
56 _output_type: PhantomData,
57 }
58 }
59
60 #[must_use]
62 pub fn then<T>(self, transformer: Box<dyn TypedTransformer<I, T>>) -> TypeSafeComposer<T, O>
63 where
64 T: CompositionType + Send + Sync + 'static,
65 {
66 let stage = TypedCompositionStage {
67 stage_id: format!("stage_{}", self.stages.len()),
68 input_type: I::type_name(),
69 output_type: T::type_name(),
70 transformer: Box::new(transformer),
71 type_constraints: self.collect_stage_constraints(),
72 };
73
74 let mut new_composer = TypeSafeComposer::<T, O> {
75 stages: self.stages,
76 type_constraints: self.type_constraints,
77 metadata: self.metadata,
78 _input_type: PhantomData,
79 _output_type: PhantomData,
80 };
81
82 new_composer.stages.push(stage);
83 new_composer
84 }
85
86 #[must_use]
88 pub fn branch<B>(self, branch: ParallelBranch<I, B>) -> Self
89 where
90 B: CompositionType + Send + Sync + 'static,
91 {
92 self
94 }
95
96 pub fn conditional<P>(self, predicate: P, true_branch: Self, false_branch: Self) -> Self
98 where
99 P: TypePredicate<I> + Send + Sync + 'static,
100 {
101 self
103 }
104
105 pub fn build(self) -> SklResult<TypedComposition<I, O>> {
107 self.validate_type_safety()?;
108
109 Ok(TypedComposition {
110 composition_id: uuid::Uuid::new_v4().to_string(),
111 stages: self.stages,
112 type_constraints: self.type_constraints,
113 metadata: self.metadata,
114 _input_type: PhantomData,
115 _output_type: PhantomData,
116 })
117 }
118
119 fn validate_type_safety(&self) -> SklResult<()> {
121 for i in 0..self.stages.len() - 1 {
123 let current_output = &self.stages[i].output_type;
124 let next_input = &self.stages[i + 1].input_type;
125
126 if !self.are_types_compatible(current_output, next_input) {
127 return Err(SklearsError::InvalidInput(format!(
128 "Type mismatch between stages {} and {}: {} -> {}",
129 i,
130 i + 1,
131 current_output,
132 next_input
133 )));
134 }
135 }
136
137 if let Some(first_stage) = self.stages.first() {
139 if first_stage.input_type != I::type_name() {
140 return Err(SklearsError::InvalidInput(format!(
141 "Input type mismatch: expected {}, got {}",
142 I::type_name(),
143 first_stage.input_type
144 )));
145 }
146 }
147
148 if let Some(last_stage) = self.stages.last() {
149 if last_stage.output_type != O::type_name() {
150 return Err(SklearsError::InvalidInput(format!(
151 "Output type mismatch: expected {}, got {}",
152 O::type_name(),
153 last_stage.output_type
154 )));
155 }
156 }
157
158 Ok(())
159 }
160
161 fn are_types_compatible(&self, output_type: &str, input_type: &str) -> bool {
162 output_type == input_type || self.type_constraints.has_coercion(output_type, input_type)
165 }
166
167 fn collect_stage_constraints(&self) -> Vec<TypeConstraint> {
168 Vec::new()
170 }
171}
172
173#[derive(Debug)]
178pub struct FunctionalComposer {
179 composition_chain: Vec<Box<dyn CompositionFunction>>,
181 monad_transformers: Vec<Box<dyn MonadTransformer>>,
183 applicative_functors: Vec<Box<dyn ApplicativeFunctor>>,
185 morphisms: Vec<CategoryMorphism>,
187}
188
189impl FunctionalComposer {
190 #[must_use]
192 pub fn new() -> Self {
193 Self {
194 composition_chain: Vec::new(),
195 monad_transformers: Vec::new(),
196 applicative_functors: Vec::new(),
197 morphisms: Vec::new(),
198 }
199 }
200
201 #[must_use]
203 pub fn compose<A, B, C>(
204 self,
205 f: Box<dyn Fn(A) -> B + Send + Sync>,
206 g: Box<dyn Fn(B) -> C + Send + Sync>,
207 ) -> Self {
208 self
210 }
211
212 pub fn fmap<F, A, B>(self, functor: F) -> Self
214 where
215 F: Functor<A, B> + Send + Sync + 'static,
216 {
217 self
219 }
220
221 pub fn bind<M, A, B>(self, monad: M) -> Self
223 where
224 M: Monad<A, B> + Send + Sync + 'static,
225 {
226 self
228 }
229
230 pub fn apply<A, F, B>(self, applicative: A) -> Self
232 where
233 A: Applicative<F, B> + Send + Sync + 'static,
234 F: Fn(F) -> B + Send + Sync + 'static,
235 {
236 self
238 }
239
240 #[must_use]
242 pub fn morphism(mut self, morphism: CategoryMorphism) -> Self {
243 self.morphisms.push(morphism);
244 self
245 }
246
247 #[must_use]
249 pub fn build(self) -> FunctionalComposition {
250 FunctionalComposition {
252 composition_id: uuid::Uuid::new_v4().to_string(),
253 composition_chain: self.composition_chain,
254 monad_transformers: self.monad_transformers,
255 applicative_functors: self.applicative_functors,
256 morphisms: self.morphisms,
257 }
258 }
259}
260
261#[derive(Debug)]
266pub struct AlgebraicComposer {
267 sum_types: Vec<SumTypeComposition>,
269 product_types: Vec<ProductTypeComposition>,
271 pattern_matchers: Vec<Box<dyn PatternMatcher>>,
273 algebraic_ops: Vec<AlgebraicOperation>,
275}
276
277impl AlgebraicComposer {
278 #[must_use]
280 pub fn new() -> Self {
281 Self {
282 sum_types: Vec::new(),
283 product_types: Vec::new(),
284 pattern_matchers: Vec::new(),
285 algebraic_ops: Vec::new(),
286 }
287 }
288
289 pub fn sum_type<L, R>(mut self, left: L, right: R) -> Self
291 where
292 L: CompositionType + Send + Sync + 'static,
293 R: CompositionType + Send + Sync + 'static,
294 {
295 let sum_composition = SumTypeComposition {
296 composition_id: uuid::Uuid::new_v4().to_string(),
297 left_type: L::type_name(),
298 right_type: R::type_name(),
299 composition_rules: SumCompositionRules::default(),
300 };
301
302 self.sum_types.push(sum_composition);
303 self
304 }
305
306 #[must_use]
308 pub fn product_type<T>(mut self, types: Vec<T>) -> Self
309 where
310 T: CompositionType + Send + Sync + 'static,
311 {
312 let product_composition = ProductTypeComposition {
313 composition_id: uuid::Uuid::new_v4().to_string(),
314 component_types: types.iter().map(|t| T::type_name()).collect(),
315 composition_rules: ProductCompositionRules::default(),
316 };
317
318 self.product_types.push(product_composition);
319 self
320 }
321
322 pub fn pattern<P>(mut self, pattern_matcher: P) -> Self
324 where
325 P: PatternMatcher + Send + Sync + 'static,
326 {
327 self.pattern_matchers.push(Box::new(pattern_matcher));
328 self
329 }
330
331 #[must_use]
333 pub fn operation(mut self, operation: AlgebraicOperation) -> Self {
334 self.algebraic_ops.push(operation);
335 self
336 }
337
338 #[must_use]
340 pub fn build(self) -> AlgebraicComposition {
341 AlgebraicComposition {
343 composition_id: uuid::Uuid::new_v4().to_string(),
344 sum_types: self.sum_types,
345 product_types: self.product_types,
346 pattern_matchers: self.pattern_matchers,
347 algebraic_ops: self.algebraic_ops,
348 }
349 }
350}
351
352#[derive(Debug)]
357pub struct HigherOrderComposer {
358 meta_compositions: Vec<MetaComposition>,
360 combinators: Vec<Box<dyn CompositionCombinator>>,
362 recursive_patterns: Vec<RecursiveCompositionPattern>,
364 higher_order_transforms: Vec<Box<dyn HigherOrderTransform>>,
366}
367
368impl HigherOrderComposer {
369 #[must_use]
371 pub fn new() -> Self {
372 Self {
373 meta_compositions: Vec::new(),
374 combinators: Vec::new(),
375 recursive_patterns: Vec::new(),
376 higher_order_transforms: Vec::new(),
377 }
378 }
379
380 pub fn compose_compositions<C1, C2>(mut self, comp1: C1, comp2: C2) -> Self
382 where
383 C1: Composition + Send + Sync + 'static,
384 C2: Composition + Send + Sync + 'static,
385 {
386 let meta_composition = MetaComposition {
387 meta_id: uuid::Uuid::new_v4().to_string(),
388 compositions: vec![Box::new(comp1), Box::new(comp2)],
389 meta_rules: MetaCompositionRules::default(),
390 };
391
392 self.meta_compositions.push(meta_composition);
393 self
394 }
395
396 pub fn combinator<C>(mut self, combinator: C) -> Self
398 where
399 C: CompositionCombinator + Send + Sync + 'static,
400 {
401 self.combinators.push(Box::new(combinator));
402 self
403 }
404
405 #[must_use]
407 pub fn recursive_pattern(mut self, pattern: RecursiveCompositionPattern) -> Self {
408 self.recursive_patterns.push(pattern);
409 self
410 }
411
412 pub fn transform<T>(mut self, transform: T) -> Self
414 where
415 T: HigherOrderTransform + Send + Sync + 'static,
416 {
417 self.higher_order_transforms.push(Box::new(transform));
418 self
419 }
420
421 #[must_use]
423 pub fn build(self) -> HigherOrderComposition {
424 HigherOrderComposition {
426 composition_id: uuid::Uuid::new_v4().to_string(),
427 meta_compositions: self.meta_compositions,
428 combinators: self.combinators,
429 recursive_patterns: self.recursive_patterns,
430 higher_order_transforms: self.higher_order_transforms,
431 }
432 }
433}
434
435pub trait CompositionType {
437 fn type_name() -> String;
439
440 fn type_constraints() -> Vec<TypeConstraint>;
442
443 fn is_compatible_with(other: &str) -> bool;
445}
446
447pub trait TypedTransformer<I, O>: Send + Sync
449where
450 I: CompositionType,
451 O: CompositionType,
452{
453 fn transform(&self, input: I) -> SklResult<O>;
455
456 fn metadata(&self) -> TransformerMetadata;
458
459 fn validate(&self, input: &I) -> SklResult<()>;
461}
462
463pub trait TypePredicate<T>: Send + Sync {
465 fn evaluate(&self, input: &T) -> bool;
467
468 fn description(&self) -> String;
470}
471
472pub trait CompositionFunction: Send + Sync + std::fmt::Debug {
474 fn apply(&self, input: &PipelineData) -> SklResult<PipelineData>;
476
477 fn signature(&self) -> FunctionSignature;
479}
480
481pub trait Functor<A, B>: Send + Sync {
483 fn fmap(&self, f: Box<dyn Fn(A) -> B + Send + Sync>) -> SklResult<B>;
485}
486
487pub trait Monad<A, B>: Send + Sync {
489 fn return_value(value: A) -> Self;
491
492 fn bind(&self, f: Box<dyn Fn(A) -> Self + Send + Sync>) -> SklResult<Self>
494 where
495 Self: Sized;
496}
497
498pub trait Applicative<F, B>: Send + Sync {
500 fn apply(&self, f: F) -> SklResult<B>;
502}
503
504pub trait MonadTransformer: Send + Sync + std::fmt::Debug {
506 fn transform(&self, monad: &dyn std::any::Any) -> SklResult<Box<dyn std::any::Any>>;
508}
509
510pub trait ApplicativeFunctor: Send + Sync + std::fmt::Debug {
512 fn apply_functor(&self, value: &dyn std::any::Any) -> SklResult<Box<dyn std::any::Any>>;
514}
515
516pub trait PatternMatcher: Send + Sync + std::fmt::Debug {
518 fn match_pattern(&self, input: &PipelineData) -> SklResult<PatternMatchResult>;
520
521 fn pattern_description(&self) -> String;
523}
524
525pub trait CompositionCombinator: Send + Sync + std::fmt::Debug {
527 fn combine(&self, compositions: Vec<Box<dyn Composition>>) -> SklResult<Box<dyn Composition>>;
529
530 fn combinator_metadata(&self) -> CombinatorMetadata;
532}
533
534pub trait HigherOrderTransform: Send + Sync + std::fmt::Debug {
536 fn transform(&self, composition: Box<dyn Composition>) -> SklResult<Box<dyn Composition>>;
538
539 fn transform_metadata(&self) -> TransformMetadata;
541}
542
543pub trait Composition: Send + Sync + std::fmt::Debug {
545 fn execute(&self, input: PipelineData) -> SklResult<PipelineData>;
547
548 fn composition_metadata(&self) -> CompositionMetadata;
550
551 fn validate(&self) -> SklResult<()>;
553}
554
555#[derive(Debug)]
557pub struct TypedCompositionStage {
558 pub stage_id: String,
560 pub input_type: String,
562 pub output_type: String,
564 pub transformer: Box<dyn std::any::Any + Send + Sync>,
566 pub type_constraints: Vec<TypeConstraint>,
568}
569
570#[derive(Debug)]
572pub struct TypedComposition<I, O> {
573 pub composition_id: String,
575 pub stages: Vec<TypedCompositionStage>,
577 pub type_constraints: TypeConstraints,
579 pub metadata: CompositionMetadata,
581 pub _input_type: PhantomData<I>,
583 pub _output_type: PhantomData<O>,
584}
585
586#[derive(Debug)]
588pub struct FunctionalComposition {
589 pub composition_id: String,
591 pub composition_chain: Vec<Box<dyn CompositionFunction>>,
593 pub monad_transformers: Vec<Box<dyn MonadTransformer>>,
595 pub applicative_functors: Vec<Box<dyn ApplicativeFunctor>>,
597 pub morphisms: Vec<CategoryMorphism>,
599}
600
601#[derive(Debug)]
603pub struct AlgebraicComposition {
604 pub composition_id: String,
606 pub sum_types: Vec<SumTypeComposition>,
608 pub product_types: Vec<ProductTypeComposition>,
610 pub pattern_matchers: Vec<Box<dyn PatternMatcher>>,
612 pub algebraic_ops: Vec<AlgebraicOperation>,
614}
615
616#[derive(Debug)]
618pub struct HigherOrderComposition {
619 pub composition_id: String,
621 pub meta_compositions: Vec<MetaComposition>,
623 pub combinators: Vec<Box<dyn CompositionCombinator>>,
625 pub recursive_patterns: Vec<RecursiveCompositionPattern>,
627 pub higher_order_transforms: Vec<Box<dyn HigherOrderTransform>>,
629}
630
631#[derive(Debug, Clone)]
633pub struct TypeConstraints {
634 pub compatibility_rules: HashMap<String, Vec<String>>,
636 pub coercion_rules: HashMap<String, String>,
638 pub custom_validators: Vec<String>,
640}
641
642impl TypeConstraints {
643 #[must_use]
644 pub fn new() -> Self {
645 Self {
646 compatibility_rules: HashMap::new(),
647 coercion_rules: HashMap::new(),
648 custom_validators: Vec::new(),
649 }
650 }
651
652 #[must_use]
653 pub fn has_coercion(&self, from_type: &str, to_type: &str) -> bool {
654 self.coercion_rules
655 .get(from_type)
656 .is_some_and(|target| target == to_type)
657 }
658}
659
660#[derive(Debug, Clone)]
662pub struct TypeConstraint {
663 pub name: String,
665 pub constraint_type: ConstraintType,
667 pub parameters: HashMap<String, String>,
669}
670
671#[derive(Debug, Clone)]
673pub enum ConstraintType {
674 Equality,
676 Compatibility,
678 Coercion,
680 Custom(String),
682}
683
684pub struct ParallelBranch<I, O> {
686 pub branch_id: String,
688 pub transformer: Box<dyn TypedTransformer<I, O>>,
690 pub weight: f64,
692 pub _input_type: PhantomData<I>,
694 pub _output_type: PhantomData<O>,
695}
696
697impl<I, O> std::fmt::Debug for ParallelBranch<I, O> {
698 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
699 f.debug_struct("ParallelBranch")
700 .field("branch_id", &self.branch_id)
701 .field("transformer", &"<transformer>")
702 .field("weight", &self.weight)
703 .field("_input_type", &self._input_type)
704 .field("_output_type", &self._output_type)
705 .finish()
706 }
707}
708
709#[derive(Debug, Clone)]
711pub struct SumTypeComposition {
712 pub composition_id: String,
714 pub left_type: String,
716 pub right_type: String,
718 pub composition_rules: SumCompositionRules,
720}
721
722#[derive(Debug, Clone)]
724pub struct ProductTypeComposition {
725 pub composition_id: String,
727 pub component_types: Vec<String>,
729 pub composition_rules: ProductCompositionRules,
731}
732
733#[derive(Debug)]
735pub struct MetaComposition {
736 pub meta_id: String,
738 pub compositions: Vec<Box<dyn Composition>>,
740 pub meta_rules: MetaCompositionRules,
742}
743
744#[derive(Debug, Clone)]
746pub struct CategoryMorphism {
747 pub morphism_id: String,
749 pub source: String,
751 pub target: String,
753 pub properties: MorphismProperties,
755}
756
757#[derive(Debug, Clone)]
759pub struct AlgebraicOperation {
760 pub operation_id: String,
762 pub operation_type: AlgebraicOperationType,
764 pub parameters: HashMap<String, serde_json::Value>,
766}
767
768#[derive(Debug, Clone)]
770pub struct RecursiveCompositionPattern {
771 pub pattern_id: String,
773 pub pattern_type: RecursivePatternType,
775 pub base_case: String,
777 pub recursive_case: String,
779}
780
781#[derive(Debug, Clone)]
783pub struct CompositionMetadata {
784 pub created_at: Instant,
786 pub name: Option<String>,
788 pub description: Option<String>,
790 pub custom_metadata: HashMap<String, String>,
792}
793
794impl CompositionMetadata {
795 #[must_use]
796 pub fn new() -> Self {
797 Self {
798 created_at: Instant::now(),
799 name: None,
800 description: None,
801 custom_metadata: HashMap::new(),
802 }
803 }
804}
805
806#[derive(Debug, Clone)]
808pub struct TransformerMetadata {
809 pub name: String,
811 pub input_type: String,
813 pub output_type: String,
815 pub version: String,
817}
818
819#[derive(Debug, Clone)]
821pub struct FunctionSignature {
822 pub name: String,
824 pub input_types: Vec<String>,
826 pub output_type: String,
828 pub side_effects: Vec<String>,
830}
831
832#[derive(Debug, Clone)]
834pub struct PatternMatchResult {
835 pub matched: bool,
837 pub extracted_values: HashMap<String, serde_json::Value>,
839 pub next_action: String,
841}
842
843#[derive(Debug, Clone)]
845pub struct CombinatorMetadata {
846 pub name: String,
848 pub combinator_type: String,
850 pub associativity: Associativity,
852}
853
854#[derive(Debug, Clone)]
856pub struct TransformMetadata {
857 pub name: String,
859 pub transform_type: String,
861 pub order: u32,
863}
864
865#[derive(Debug, Clone)]
867pub struct SumCompositionRules {
868 pub default_branch: SumBranch,
870 pub selection_strategy: BranchSelectionStrategy,
872}
873
874impl Default for SumCompositionRules {
875 fn default() -> Self {
876 Self {
877 default_branch: SumBranch::Left,
878 selection_strategy: BranchSelectionStrategy::TypeBased,
879 }
880 }
881}
882
883#[derive(Debug, Clone)]
885pub struct ProductCompositionRules {
886 pub composition_strategy: ProductCompositionStrategy,
888 pub field_access: FieldAccessRules,
890}
891
892impl Default for ProductCompositionRules {
893 fn default() -> Self {
894 Self {
895 composition_strategy: ProductCompositionStrategy::Parallel,
896 field_access: FieldAccessRules::ByIndex,
897 }
898 }
899}
900
901#[derive(Debug, Clone)]
903pub struct MetaCompositionRules {
904 pub composition_order: CompositionOrder,
906 pub error_handling: MetaErrorHandling,
908}
909
910impl Default for MetaCompositionRules {
911 fn default() -> Self {
912 Self {
913 composition_order: CompositionOrder::Sequential,
914 error_handling: MetaErrorHandling::FailFast,
915 }
916 }
917}
918
919#[derive(Debug, Clone)]
921pub struct MorphismProperties {
922 pub is_identity: bool,
924 pub is_composable: bool,
926 pub morphism_type: MorphismType,
928}
929
930#[derive(Debug, Clone)]
932pub enum SumBranch {
933 Left,
935 Right,
937}
938
939#[derive(Debug, Clone)]
940pub enum BranchSelectionStrategy {
941 TypeBased,
943 ValueBased,
945 Custom(String),
947}
948
949#[derive(Debug, Clone)]
950pub enum ProductCompositionStrategy {
951 Sequential,
953 Parallel,
955 Adaptive,
957}
958
959#[derive(Debug, Clone)]
960pub enum FieldAccessRules {
961 ByIndex,
963 ByName,
965 ByType,
967}
968
969#[derive(Debug, Clone)]
970pub enum CompositionOrder {
971 Sequential,
973 Parallel,
975 Dependency,
977}
978
979#[derive(Debug, Clone)]
980pub enum MetaErrorHandling {
981 FailFast,
983 Continue,
985 Retry,
987}
988
989#[derive(Debug, Clone)]
990pub enum AlgebraicOperationType {
991 Union,
993 Intersection,
995 Product,
997 Quotient,
999 Custom(String),
1001}
1002
1003#[derive(Debug, Clone)]
1004pub enum RecursivePatternType {
1005 TailRecursion,
1007 TreeRecursion,
1009 MutualRecursion,
1011 Custom(String),
1013}
1014
1015#[derive(Debug, Clone)]
1016pub enum MorphismType {
1017 Functor,
1019 NaturalTransformation,
1021 Adjunction,
1023 Custom(String),
1025}
1026
1027#[derive(Debug, Clone)]
1028pub enum Associativity {
1029 Left,
1031 Right,
1033 None,
1034}
1035
1036#[derive(Debug, Error)]
1038pub enum AdvancedCompositionError {
1039 #[error("Type mismatch: expected {expected}, got {actual}")]
1040 TypeMismatch { expected: String, actual: String },
1041
1042 #[error("Invalid composition: {0}")]
1043 InvalidComposition(String),
1044
1045 #[error("Pattern match failed: {0}")]
1046 PatternMatchFailed(String),
1047
1048 #[error("Algebraic operation failed: {0}")]
1049 AlgebraicOperationFailed(String),
1050
1051 #[error("Higher-order transformation failed: {0}")]
1052 HigherOrderTransformFailed(String),
1053}
1054
1055impl Default for TypeConstraints {
1056 fn default() -> Self {
1057 Self::new()
1058 }
1059}
1060
1061impl Default for CompositionMetadata {
1062 fn default() -> Self {
1063 Self::new()
1064 }
1065}
1066
1067impl Default for FunctionalComposer {
1068 fn default() -> Self {
1069 Self::new()
1070 }
1071}
1072
1073impl Default for AlgebraicComposer {
1074 fn default() -> Self {
1075 Self::new()
1076 }
1077}
1078
1079impl Default for HigherOrderComposer {
1080 fn default() -> Self {
1081 Self::new()
1082 }
1083}
1084
1085#[allow(non_snake_case)]
1086#[cfg(test)]
1087mod tests {
1088 use super::*;
1089 use std::time::Duration;
1090
1091 struct TestType;
1093
1094 impl CompositionType for TestType {
1095 fn type_name() -> String {
1096 "TestType".to_string()
1097 }
1098
1099 fn type_constraints() -> Vec<TypeConstraint> {
1100 Vec::new()
1101 }
1102
1103 fn is_compatible_with(_other: &str) -> bool {
1104 true
1105 }
1106 }
1107
1108 struct TestTransformer;
1109
1110 impl TypedTransformer<TestType, TestType> for TestTransformer {
1111 fn transform(&self, input: TestType) -> SklResult<TestType> {
1112 Ok(input)
1113 }
1114
1115 fn metadata(&self) -> TransformerMetadata {
1116 TransformerMetadata {
1118 name: "TestTransformer".to_string(),
1119 input_type: "TestType".to_string(),
1120 output_type: "TestType".to_string(),
1121 version: "1.0.0".to_string(),
1122 }
1123 }
1124
1125 fn validate(&self, _input: &TestType) -> SklResult<()> {
1126 Ok(())
1127 }
1128 }
1129
1130 #[test]
1131 fn test_type_constraints() {
1132 let mut constraints = TypeConstraints::new();
1133 constraints
1134 .coercion_rules
1135 .insert("String".to_string(), "Number".to_string());
1136
1137 assert!(constraints.has_coercion("String", "Number"));
1138 assert!(!constraints.has_coercion("Number", "String"));
1139 }
1140
1141 #[test]
1142 fn test_composition_metadata() {
1143 let metadata = CompositionMetadata::new();
1144 assert!(metadata.created_at.elapsed() < Duration::from_secs(1));
1145 assert!(metadata.name.is_none());
1146 }
1147
1148 #[test]
1149 fn test_functional_composer() {
1150 let composer = FunctionalComposer::new();
1151 let composition = composer.build();
1152
1153 assert!(!composition.composition_id.is_empty());
1154 assert_eq!(composition.composition_chain.len(), 0);
1155 }
1156
1157 #[test]
1158 fn test_algebraic_composer() {
1159 let composer = AlgebraicComposer::new().sum_type(TestType, TestType);
1160
1161 let composition = composer.build();
1162 assert!(!composition.composition_id.is_empty());
1163 assert_eq!(composition.sum_types.len(), 1);
1164 }
1165
1166 #[test]
1167 fn test_higher_order_composer() {
1168 let composer = HigherOrderComposer::new();
1169 let composition = composer.build();
1170
1171 assert!(!composition.composition_id.is_empty());
1172 assert_eq!(composition.meta_compositions.len(), 0);
1173 }
1174}