1#[macro_export]
28macro_rules! with_task_registry {
29 ($callback:path) => {
30 $callback! {
31 TextDetection {
32 output: $crate::domain::tasks::TextDetectionOutput,
33 adapter: $crate::domain::adapters::TextDetectionAdapter,
34 constructor: text_detection,
35 conversion: into_text_detection,
36 doc: "Text detection - locating text regions in images",
37 },
38 TextRecognition {
39 output: $crate::domain::tasks::TextRecognitionOutput,
40 adapter: $crate::domain::adapters::TextRecognitionAdapter,
41 constructor: text_recognition,
42 conversion: into_text_recognition,
43 doc: "Text recognition - converting text regions to strings",
44 },
45 DocumentOrientation {
46 output: $crate::domain::tasks::DocumentOrientationOutput,
47 adapter: $crate::domain::adapters::DocumentOrientationAdapter,
48 constructor: document_orientation,
49 conversion: into_document_orientation,
50 doc: "Document orientation classification",
51 },
52 TextLineOrientation {
53 output: $crate::domain::tasks::TextLineOrientationOutput,
54 adapter: $crate::domain::adapters::TextLineOrientationAdapter,
55 constructor: text_line_orientation,
56 conversion: into_text_line_orientation,
57 doc: "Text line orientation classification",
58 },
59 DocumentRectification {
60 output: $crate::domain::tasks::DocumentRectificationOutput,
61 adapter: $crate::domain::adapters::UVDocRectifierAdapter,
62 constructor: document_rectification,
63 conversion: into_document_rectification,
64 doc: "Document rectification/unwarp",
65 },
66 LayoutDetection {
67 output: $crate::domain::tasks::LayoutDetectionOutput,
68 adapter: $crate::domain::adapters::LayoutDetectionAdapter,
69 constructor: layout_detection,
70 conversion: into_layout_detection,
71 doc: "Layout detection/analysis",
72 },
73 TableCellDetection {
74 output: $crate::domain::tasks::TableCellDetectionOutput,
75 adapter: $crate::domain::adapters::TableCellDetectionAdapter,
76 constructor: table_cell_detection,
77 conversion: into_table_cell_detection,
78 doc: "Table cell detection - locating cells within table regions",
79 },
80 FormulaRecognition {
81 output: $crate::domain::tasks::FormulaRecognitionOutput,
82 adapter: $crate::domain::adapters::FormulaRecognitionAdapter,
83 constructor: formula_recognition,
84 conversion: into_formula_recognition,
85 doc: "Formula recognition - converting mathematical formulas to LaTeX",
86 },
87 SealTextDetection {
88 output: $crate::domain::tasks::SealTextDetectionOutput,
89 adapter: $crate::domain::adapters::SealTextDetectionAdapter,
90 constructor: seal_text_detection,
91 conversion: into_seal_text_detection,
92 doc: "Seal text detection - locating text regions in seal/stamp images",
93 },
94 TableClassification {
95 output: $crate::domain::tasks::TableClassificationOutput,
96 adapter: $crate::domain::adapters::TableClassificationAdapter,
97 constructor: table_classification,
98 conversion: into_table_classification,
99 doc: "Table classification - classifying table images as wired or wireless",
100 },
101 TableStructureRecognition {
102 output: $crate::domain::tasks::TableStructureRecognitionOutput,
103 adapter: $crate::domain::adapters::TableStructureRecognitionAdapter,
104 constructor: table_structure_recognition,
105 conversion: into_table_structure_recognition,
106 doc: "Table structure recognition - recognizing table structure as HTML with bboxes",
107 }
108 }
109 };
110}
111
112#[macro_export]
117macro_rules! impl_task_type_enum {
118 ($(
119 $task:ident {
120 output: $output:ty,
121 adapter: $adapter:ty,
122 constructor: $constructor:ident,
123 conversion: $conversion:ident,
124 doc: $doc:literal,
125 }
126 ),* $(,)?) => {
127 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
129 pub enum TaskType {
130 $(
131 #[doc = $doc]
132 $task,
133 )*
134 }
135
136 impl TaskType {
137 pub fn name(&self) -> &'static str {
139 match self {
140 $(TaskType::$task => <$output as $crate::core::traits::TaskDefinition>::TASK_NAME,)*
141 }
142 }
143 }
144 };
145}
146
147#[macro_export]
173macro_rules! with_nested {
174 ($field:expr, $type:ty, $var:ident => $body:block) => {
175 if $field.is_none() {
176 $field = Some(<$type>::new());
177 }
178 if let Some(ref mut $var) = $field {
179 $body
180 }
181 };
182}
183
184#[macro_export]
204macro_rules! metrics {
205 ($success:expr, $failure:expr, $start_time:expr; $($key:ident = $value:expr),*) => {
207 {
208 let mut metrics = $crate::pipeline::stages::StageMetrics::new($success, $failure);
209 metrics = metrics.with_processing_time($start_time.elapsed());
210 $(
211 metrics = metrics.with_info(stringify!($key), $value.to_string());
212 )*
213 metrics
214 }
215 };
216 ($success:expr, $failure:expr; $($key:ident = $value:expr),*) => {
218 {
219 let mut metrics = $crate::pipeline::stages::StageMetrics::new($success, $failure);
220 $(
221 metrics = metrics.with_info(stringify!($key), $value.to_string());
222 )*
223 metrics
224 }
225 };
226}
227
228#[macro_export]
262macro_rules! impl_complete_builder {
263 (
265 builder: $builder:ident,
266 config_field: $config_field:ident,
267 simple_setters: {
268 $($simple_field:ident: $simple_type:ty => $simple_doc:literal),* $(,)?
269 }
270 ) => {
271 impl $builder {
272 $(
273 #[doc = $simple_doc]
274 pub fn $simple_field(mut self, value: $simple_type) -> Self {
275 self.$config_field.$simple_field = Some(value);
276 self
277 }
278 )*
279 }
280 };
281
282 (
284 builder: $builder:ident,
285 config_field: $config_field:ident,
286 nested_setters: {
287 $($nested_path:ident: $nested_type:ty => {
288 $($nested_field:ident: $nested_field_type:ty => $nested_doc:literal),* $(,)?
289 }),* $(,)?
290 }
291 ) => {
292 impl $builder {
293 $($(
294 #[doc = $nested_doc]
295 pub fn $nested_field(mut self, value: $nested_field_type) -> Self {
296 $crate::with_nested!(self.$config_field.$nested_path, $nested_type, config => {
297 config.$nested_field = Some(value);
298 });
299 self
300 }
301 )*)*
302 }
303 };
304
305 (
307 builder: $builder:ident,
308 config_field: $config_field:ident,
309 enable_methods: {
310 $($enable_method:ident => $enable_field:ident: $enable_type:ty => $enable_doc:literal),* $(,)?
311 }
312 ) => {
313 impl $builder {
314 $(
315 #[doc = $enable_doc]
316 pub fn $enable_method(mut self) -> Self {
317 self.$config_field.$enable_field = Some(<$enable_type>::default());
318 self
319 }
320 )*
321 }
322 };
323}
324
325#[macro_export]
327macro_rules! impl_config_new_and_with_common {
328 (
329 $Config:ident,
330 common_defaults: ($model_name_opt:expr, $batch_size_opt:expr),
331 fields: { $( $field:ident : $default_expr:expr ),* $(,)? }
332 ) => {
333 impl $Config {
334 pub fn new() -> Self {
336 Self {
337 common: $crate::core::config::builder::ModelInferenceConfig::with_defaults(
338 $model_name_opt, $batch_size_opt
339 ),
340 $( $field: $default_expr ),*
341 }
342 }
343 pub fn with_common(common: $crate::core::config::builder::ModelInferenceConfig) -> Self {
345 Self {
346 common,
347 $( $field: $default_expr ),*
348 }
349 }
350 }
351 };
352}
353
354#[macro_export]
356macro_rules! impl_common_builder_methods {
357 ($Builder:ident, $common_field:ident) => {
358 impl $Builder {
359 pub fn model_path(mut self, model_path: impl Into<std::path::PathBuf>) -> Self {
361 self.$common_field = self.$common_field.model_path(model_path);
362 self
363 }
364 pub fn model_name(mut self, model_name: impl Into<String>) -> Self {
366 self.$common_field = self.$common_field.model_name(model_name);
367 self
368 }
369 pub fn batch_size(mut self, batch_size: usize) -> Self {
371 self.$common_field = self.$common_field.batch_size(batch_size);
372 self
373 }
374 pub fn enable_logging(mut self, enable: bool) -> Self {
376 self.$common_field = self.$common_field.enable_logging(enable);
377 self
378 }
379 pub fn ort_session(
381 mut self,
382 config: $crate::core::config::onnx::OrtSessionConfig,
383 ) -> Self {
384 self.$common_field = self.$common_field.ort_session(config);
385 self
386 }
387 }
388 };
389}
390
391#[macro_export]
395macro_rules! common_builder_methods {
396 ($common_field:ident) => {
397 pub fn model_path(mut self, model_path: impl Into<std::path::PathBuf>) -> Self {
399 self.$common_field = self.$common_field.model_path(model_path);
400 self
401 }
402 pub fn model_name(mut self, model_name: impl Into<String>) -> Self {
404 self.$common_field = self.$common_field.model_name(model_name);
405 self
406 }
407 pub fn batch_size(mut self, batch_size: usize) -> Self {
409 self.$common_field = self.$common_field.batch_size(batch_size);
410 self
411 }
412 pub fn enable_logging(mut self, enable: bool) -> Self {
414 self.$common_field = self.$common_field.enable_logging(enable);
415 self
416 }
417 pub fn ort_session(mut self, config: $crate::core::config::onnx::OrtSessionConfig) -> Self {
419 self.$common_field = self.$common_field.ort_session(config);
420 self
421 }
422 };
423}
424
425#[doc(hidden)]
439#[macro_export]
440macro_rules! __impl_adapter_builder_common {
441 (
442 builder_name: $Builder:ident,
443 adapter_name: $Adapter:ident,
444 config_type: $Config:ty,
445 adapter_type: $adapter_type_str:literal,
446 adapter_desc: $adapter_desc:literal,
447 task_type: $TaskType:ident,
448
449 fields: {
450 $($field_vis:vis $field_name:ident : $field_ty:ty = $field_default:expr),*
451 $(,)?
452 },
453
454 methods: {
455 $($method:item)*
456 }
457 ) => {
458 #[doc = $adapter_desc]
461 #[derive(Debug)]
462 pub struct $Builder {
463 config: $crate::domain::adapters::builder_config::AdapterBuilderConfig<$Config>,
465 $($field_vis $field_name : $field_ty),*
466 }
467
468 impl $Builder {
469 pub fn new() -> Self {
471 Self {
472 config: $crate::domain::adapters::builder_config::AdapterBuilderConfig::default(),
473 $($field_name : $field_default),*
474 }
475 }
476
477 pub fn base_adapter_info() -> $crate::core::traits::adapter::AdapterInfo {
482 $crate::core::traits::adapter::AdapterInfo::new(
483 $adapter_type_str,
484 $crate::core::traits::task::TaskType::$TaskType,
485 $adapter_desc,
486 )
487 }
488
489 $($method)*
491 }
492
493 impl Default for $Builder {
494 fn default() -> Self {
495 Self::new()
496 }
497 }
498
499 impl $crate::core::traits::OrtConfigurable for $Builder {
500 fn with_ort_config(mut self, config: $crate::core::config::OrtSessionConfig) -> Self {
501 self.config = self.config.with_ort_config(config);
502 self
503 }
504 }
505 };
506}
507
508#[macro_export]
558macro_rules! impl_adapter_builder {
559 (
561 builder_name: $Builder:ident,
562 adapter_name: $Adapter:ident,
563 config_type: $Config:ty,
564 adapter_type: $adapter_type_str:literal,
565 adapter_desc: $adapter_desc:literal,
566 task_type: $TaskType:ident,
567
568 fields: {
569 $($field_vis:vis $field_name:ident : $field_ty:ty = $field_default:expr),*
570 $(,)?
571 },
572
573 methods: {
574 $($method:item)*
575 }
576
577 build: $build_closure:expr,
578 ) => {
579 $crate::__impl_adapter_builder_common! {
581 builder_name: $Builder,
582 adapter_name: $Adapter,
583 config_type: $Config,
584 adapter_type: $adapter_type_str,
585 adapter_desc: $adapter_desc,
586 task_type: $TaskType,
587
588 fields: {
589 $($field_vis $field_name : $field_ty = $field_default),*
590 },
591
592 methods: {
593 pub fn with_config(mut self, config: $Config) -> Self {
595 self.config = self.config.with_task_config(config);
596 self
597 }
598
599 $($method)*
600 }
601 }
602
603 impl $crate::core::traits::adapter::AdapterBuilder for $Builder {
605 type Config = $Config;
606 type Adapter = $Adapter;
607
608 fn build(
609 self,
610 model_source: impl Into<$crate::core::ModelSource>,
611 ) -> Result<Self::Adapter, $crate::core::OCRError> {
612 let build_fn: fn(Self, $crate::core::ModelSource) -> Result<$Adapter, $crate::core::OCRError> = $build_closure;
613 build_fn(self, model_source.into())
614 }
615
616 fn with_config(mut self, config: Self::Config) -> Self {
617 self.config = self.config.with_task_config(config);
618 self
619 }
620
621 fn adapter_type(&self) -> &str {
622 $adapter_type_str
623 }
624 }
625 };
626
627 (
629 builder_name: $Builder:ident,
630 adapter_name: $Adapter:ident,
631 config_type: $Config:ty,
632 adapter_type: $adapter_type_str:literal,
633 adapter_desc: $adapter_desc:literal,
634 task_type: $TaskType:ident,
635
636 methods: {
637 $($method:item)*
638 }
639
640 build: $build_closure:expr,
641 ) => {
642 impl_adapter_builder! {
643 builder_name: $Builder,
644 adapter_name: $Adapter,
645 config_type: $Config,
646 adapter_type: $adapter_type_str,
647 adapter_desc: $adapter_desc,
648 task_type: $TaskType,
649
650 fields: {},
651
652 methods: {
653 $($method)*
654 }
655
656 build: $build_closure,
657 }
658 };
659
660 (
662 builder_name: $Builder:ident,
663 adapter_name: $Adapter:ident,
664 config_type: $Config:ty,
665 adapter_type: $adapter_type_str:literal,
666 adapter_desc: $adapter_desc:literal,
667 task_type: $TaskType:ident,
668
669 fields: {
670 $($field_vis:vis $field_name:ident : $field_ty:ty = $field_default:expr),*
671 $(,)?
672 }
673
674 build: $build_closure:expr,
675 ) => {
676 impl_adapter_builder! {
677 builder_name: $Builder,
678 adapter_name: $Adapter,
679 config_type: $Config,
680 adapter_type: $adapter_type_str,
681 adapter_desc: $adapter_desc,
682 task_type: $TaskType,
683
684 fields: {
685 $($field_vis $field_name : $field_ty = $field_default),*
686 },
687
688 methods: {}
689
690 build: $build_closure,
691 }
692 };
693
694 (
696 builder_name: $Builder:ident,
697 adapter_name: $Adapter:ident,
698 config_type: $Config:ty,
699 adapter_type: $adapter_type_str:literal,
700 adapter_desc: $adapter_desc:literal,
701 task_type: $TaskType:ident
702
703 build: $build_closure:expr,
704 ) => {
705 impl_adapter_builder! {
706 builder_name: $Builder,
707 adapter_name: $Adapter,
708 config_type: $Config,
709 adapter_type: $adapter_type_str,
710 adapter_desc: $adapter_desc,
711 task_type: $TaskType,
712
713 fields: {},
714
715 methods: {}
716
717 build: $build_closure,
718 }
719 };
720
721 (
723 builder_name: $Builder:ident,
724 adapter_name: $Adapter:ident,
725 config_type: $Config:ty,
726 adapter_type: $adapter_type_str:literal,
727 adapter_desc: $adapter_desc:literal,
728 task_type: $TaskType:ident,
729
730 fields: {
731 $($field_vis:vis $field_name:ident : $field_ty:ty = $field_default:expr),*
732 $(,)?
733 },
734
735 methods: {
736 $($method:item)*
737 }
738
739 overrides: {
740 with_config: $with_config_closure:expr,
741 adapter_type: $adapter_type_closure:expr,
742 }
743
744 build: $build_closure:expr,
745 ) => {
746 $crate::__impl_adapter_builder_common! {
748 builder_name: $Builder,
749 adapter_name: $Adapter,
750 config_type: $Config,
751 adapter_type: $adapter_type_str,
752 adapter_desc: $adapter_desc,
753 task_type: $TaskType,
754
755 fields: {
756 $($field_vis $field_name : $field_ty = $field_default),*
757 },
758
759 methods: {
760 $($method)*
761 }
762 }
763
764 impl $crate::core::traits::adapter::AdapterBuilder for $Builder {
766 type Config = $Config;
767 type Adapter = $Adapter;
768
769 fn build(
770 self,
771 model_source: impl Into<$crate::core::ModelSource>,
772 ) -> Result<Self::Adapter, $crate::core::OCRError> {
773 let build_fn: fn(Self, $crate::core::ModelSource) -> Result<$Adapter, $crate::core::OCRError> = $build_closure;
774 build_fn(self, model_source.into())
775 }
776
777 fn with_config(self, config: Self::Config) -> Self {
778 let with_config_fn: fn(Self, Self::Config) -> Self = $with_config_closure;
779 with_config_fn(self, config)
780 }
781
782 fn adapter_type(&self) -> &str {
783 let adapter_type_fn: fn(&Self) -> &str = $adapter_type_closure;
784 adapter_type_fn(self)
785 }
786 }
787 };
788
789 (
791 builder_name: $Builder:ident,
792 adapter_name: $Adapter:ident,
793 config_type: $Config:ty,
794 adapter_type: $adapter_type_str:literal,
795 adapter_desc: $adapter_desc:literal,
796 task_type: $TaskType:ident,
797
798 fields: {
799 $($field_vis:vis $field_name:ident : $field_ty:ty = $field_default:expr),*
800 $(,)?
801 },
802
803 methods: {
804 $($method:item)*
805 }
806
807 overrides: {
808 with_config: $with_config_closure:expr,
809 }
810
811 build: $build_closure:expr,
812 ) => {
813 $crate::__impl_adapter_builder_common! {
815 builder_name: $Builder,
816 adapter_name: $Adapter,
817 config_type: $Config,
818 adapter_type: $adapter_type_str,
819 adapter_desc: $adapter_desc,
820 task_type: $TaskType,
821
822 fields: {
823 $($field_vis $field_name : $field_ty = $field_default),*
824 },
825
826 methods: {
827 $($method)*
828 }
829 }
830
831 impl $crate::core::traits::adapter::AdapterBuilder for $Builder {
833 type Config = $Config;
834 type Adapter = $Adapter;
835
836 fn build(
837 self,
838 model_source: impl Into<$crate::core::ModelSource>,
839 ) -> Result<Self::Adapter, $crate::core::OCRError> {
840 let build_fn: fn(Self, $crate::core::ModelSource) -> Result<$Adapter, $crate::core::OCRError> = $build_closure;
841 build_fn(self, model_source.into())
842 }
843
844 fn with_config(self, config: Self::Config) -> Self {
845 let with_config_fn: fn(Self, Self::Config) -> Self = $with_config_closure;
846 with_config_fn(self, config)
847 }
848
849 fn adapter_type(&self) -> &str {
850 $adapter_type_str
851 }
852 }
853 };
854}
855
856#[macro_export]
882macro_rules! apply_ort_config {
883 ($builder:expr, $ort_config:expr) => {{
884 let builder = $builder;
885 if let Some(cfg) = $ort_config {
886 builder.with_ort_config(cfg)
887 } else {
888 builder
889 }
890 }};
891}
892
893#[cfg(test)]
894mod tests {
895
896 #[derive(Debug, Default)]
898 struct TestConfig {
899 simple_field: Option<String>,
900 nested_config: Option<NestedConfig>,
901 enable_field: Option<EnabledFeature>,
902 }
903
904 #[derive(Debug, Default)]
905 struct NestedConfig {
906 nested_field: Option<i32>,
907 }
908
909 impl NestedConfig {
910 fn new() -> Self {
911 Self::default()
912 }
913 }
914
915 #[derive(Debug, Default)]
916 struct EnabledFeature {
917 _enabled: bool,
918 }
919
920 #[derive(Debug)]
922 struct TestBuilder {
923 config: TestConfig,
924 }
925
926 impl TestBuilder {
927 fn new() -> Self {
928 Self {
929 config: TestConfig::default(),
930 }
931 }
932
933 fn get_config(&self) -> &TestConfig {
934 &self.config
935 }
936 }
937
938 impl_complete_builder! {
940 builder: TestBuilder,
941 config_field: config,
942 simple_setters: {
943 simple_field: String => "Sets a simple field value",
944 }
945 }
946
947 impl_complete_builder! {
948 builder: TestBuilder,
949 config_field: config,
950 nested_setters: {
951 nested_config: NestedConfig => {
952 nested_field: i32 => "Sets a nested field value",
953 },
954 }
955 }
956
957 impl_complete_builder! {
958 builder: TestBuilder,
959 config_field: config,
960 enable_methods: {
961 enable_feature => enable_field: EnabledFeature => "Enables a feature with default configuration",
962 }
963 }
964
965 #[test]
966 fn test_impl_complete_builder_nested_setter() {
967 let builder = TestBuilder::new().nested_field(42);
968
969 assert!(builder.get_config().nested_config.is_some());
970 let Some(nested) = builder.get_config().nested_config.as_ref() else {
971 panic!("expected nested_config to be Some");
972 };
973 assert_eq!(nested.nested_field, Some(42));
974 }
975
976 #[test]
977 fn test_impl_complete_builder_enable_method() {
978 let builder = TestBuilder::new().enable_feature();
979
980 assert!(builder.get_config().enable_field.is_some());
981 }
982
983 #[test]
984 fn test_impl_complete_builder_chaining() {
985 let builder = TestBuilder::new()
986 .simple_field("test".to_string())
987 .nested_field(123)
988 .enable_feature();
989
990 let config = builder.get_config();
991 assert_eq!(config.simple_field, Some("test".to_string()));
992 assert!(config.nested_config.is_some());
993 let Some(nested) = config.nested_config.as_ref() else {
994 panic!("expected nested_config to be Some");
995 };
996 assert_eq!(nested.nested_field, Some(123));
997 assert!(config.enable_field.is_some());
998 }
999}