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(self, model_path: &std::path::Path) -> Result<Self::Adapter, $crate::core::OCRError> {
609 let build_fn: fn(Self, &std::path::Path) -> Result<$Adapter, $crate::core::OCRError> = $build_closure;
610 build_fn(self, model_path)
611 }
612
613 fn with_config(mut self, config: Self::Config) -> Self {
614 self.config = self.config.with_task_config(config);
615 self
616 }
617
618 fn adapter_type(&self) -> &str {
619 $adapter_type_str
620 }
621 }
622 };
623
624 (
626 builder_name: $Builder:ident,
627 adapter_name: $Adapter:ident,
628 config_type: $Config:ty,
629 adapter_type: $adapter_type_str:literal,
630 adapter_desc: $adapter_desc:literal,
631 task_type: $TaskType:ident,
632
633 methods: {
634 $($method:item)*
635 }
636
637 build: $build_closure:expr,
638 ) => {
639 impl_adapter_builder! {
640 builder_name: $Builder,
641 adapter_name: $Adapter,
642 config_type: $Config,
643 adapter_type: $adapter_type_str,
644 adapter_desc: $adapter_desc,
645 task_type: $TaskType,
646
647 fields: {},
648
649 methods: {
650 $($method)*
651 }
652
653 build: $build_closure,
654 }
655 };
656
657 (
659 builder_name: $Builder:ident,
660 adapter_name: $Adapter:ident,
661 config_type: $Config:ty,
662 adapter_type: $adapter_type_str:literal,
663 adapter_desc: $adapter_desc:literal,
664 task_type: $TaskType:ident,
665
666 fields: {
667 $($field_vis:vis $field_name:ident : $field_ty:ty = $field_default:expr),*
668 $(,)?
669 }
670
671 build: $build_closure:expr,
672 ) => {
673 impl_adapter_builder! {
674 builder_name: $Builder,
675 adapter_name: $Adapter,
676 config_type: $Config,
677 adapter_type: $adapter_type_str,
678 adapter_desc: $adapter_desc,
679 task_type: $TaskType,
680
681 fields: {
682 $($field_vis $field_name : $field_ty = $field_default),*
683 },
684
685 methods: {}
686
687 build: $build_closure,
688 }
689 };
690
691 (
693 builder_name: $Builder:ident,
694 adapter_name: $Adapter:ident,
695 config_type: $Config:ty,
696 adapter_type: $adapter_type_str:literal,
697 adapter_desc: $adapter_desc:literal,
698 task_type: $TaskType:ident
699
700 build: $build_closure:expr,
701 ) => {
702 impl_adapter_builder! {
703 builder_name: $Builder,
704 adapter_name: $Adapter,
705 config_type: $Config,
706 adapter_type: $adapter_type_str,
707 adapter_desc: $adapter_desc,
708 task_type: $TaskType,
709
710 fields: {},
711
712 methods: {}
713
714 build: $build_closure,
715 }
716 };
717
718 (
720 builder_name: $Builder:ident,
721 adapter_name: $Adapter:ident,
722 config_type: $Config:ty,
723 adapter_type: $adapter_type_str:literal,
724 adapter_desc: $adapter_desc:literal,
725 task_type: $TaskType:ident,
726
727 fields: {
728 $($field_vis:vis $field_name:ident : $field_ty:ty = $field_default:expr),*
729 $(,)?
730 },
731
732 methods: {
733 $($method:item)*
734 }
735
736 overrides: {
737 with_config: $with_config_closure:expr,
738 adapter_type: $adapter_type_closure:expr,
739 }
740
741 build: $build_closure:expr,
742 ) => {
743 $crate::__impl_adapter_builder_common! {
745 builder_name: $Builder,
746 adapter_name: $Adapter,
747 config_type: $Config,
748 adapter_type: $adapter_type_str,
749 adapter_desc: $adapter_desc,
750 task_type: $TaskType,
751
752 fields: {
753 $($field_vis $field_name : $field_ty = $field_default),*
754 },
755
756 methods: {
757 $($method)*
758 }
759 }
760
761 impl $crate::core::traits::adapter::AdapterBuilder for $Builder {
763 type Config = $Config;
764 type Adapter = $Adapter;
765
766 fn build(self, model_path: &std::path::Path) -> Result<Self::Adapter, $crate::core::OCRError> {
767 let build_fn: fn(Self, &std::path::Path) -> Result<$Adapter, $crate::core::OCRError> = $build_closure;
768 build_fn(self, model_path)
769 }
770
771 fn with_config(self, config: Self::Config) -> Self {
772 let with_config_fn: fn(Self, Self::Config) -> Self = $with_config_closure;
773 with_config_fn(self, config)
774 }
775
776 fn adapter_type(&self) -> &str {
777 let adapter_type_fn: fn(&Self) -> &str = $adapter_type_closure;
778 adapter_type_fn(self)
779 }
780 }
781 };
782
783 (
785 builder_name: $Builder:ident,
786 adapter_name: $Adapter:ident,
787 config_type: $Config:ty,
788 adapter_type: $adapter_type_str:literal,
789 adapter_desc: $adapter_desc:literal,
790 task_type: $TaskType:ident,
791
792 fields: {
793 $($field_vis:vis $field_name:ident : $field_ty:ty = $field_default:expr),*
794 $(,)?
795 },
796
797 methods: {
798 $($method:item)*
799 }
800
801 overrides: {
802 with_config: $with_config_closure:expr,
803 }
804
805 build: $build_closure:expr,
806 ) => {
807 $crate::__impl_adapter_builder_common! {
809 builder_name: $Builder,
810 adapter_name: $Adapter,
811 config_type: $Config,
812 adapter_type: $adapter_type_str,
813 adapter_desc: $adapter_desc,
814 task_type: $TaskType,
815
816 fields: {
817 $($field_vis $field_name : $field_ty = $field_default),*
818 },
819
820 methods: {
821 $($method)*
822 }
823 }
824
825 impl $crate::core::traits::adapter::AdapterBuilder for $Builder {
827 type Config = $Config;
828 type Adapter = $Adapter;
829
830 fn build(self, model_path: &std::path::Path) -> Result<Self::Adapter, $crate::core::OCRError> {
831 let build_fn: fn(Self, &std::path::Path) -> Result<$Adapter, $crate::core::OCRError> = $build_closure;
832 build_fn(self, model_path)
833 }
834
835 fn with_config(self, config: Self::Config) -> Self {
836 let with_config_fn: fn(Self, Self::Config) -> Self = $with_config_closure;
837 with_config_fn(self, config)
838 }
839
840 fn adapter_type(&self) -> &str {
841 $adapter_type_str
842 }
843 }
844 };
845}
846
847#[macro_export]
873macro_rules! apply_ort_config {
874 ($builder:expr, $ort_config:expr) => {{
875 let builder = $builder;
876 if let Some(cfg) = $ort_config {
877 builder.with_ort_config(cfg)
878 } else {
879 builder
880 }
881 }};
882}
883
884#[cfg(test)]
885mod tests {
886
887 #[derive(Debug, Default)]
889 struct TestConfig {
890 simple_field: Option<String>,
891 nested_config: Option<NestedConfig>,
892 enable_field: Option<EnabledFeature>,
893 }
894
895 #[derive(Debug, Default)]
896 struct NestedConfig {
897 nested_field: Option<i32>,
898 }
899
900 impl NestedConfig {
901 fn new() -> Self {
902 Self::default()
903 }
904 }
905
906 #[derive(Debug, Default)]
907 struct EnabledFeature {
908 _enabled: bool,
909 }
910
911 #[derive(Debug)]
913 struct TestBuilder {
914 config: TestConfig,
915 }
916
917 impl TestBuilder {
918 fn new() -> Self {
919 Self {
920 config: TestConfig::default(),
921 }
922 }
923
924 fn get_config(&self) -> &TestConfig {
925 &self.config
926 }
927 }
928
929 impl_complete_builder! {
931 builder: TestBuilder,
932 config_field: config,
933 simple_setters: {
934 simple_field: String => "Sets a simple field value",
935 }
936 }
937
938 impl_complete_builder! {
939 builder: TestBuilder,
940 config_field: config,
941 nested_setters: {
942 nested_config: NestedConfig => {
943 nested_field: i32 => "Sets a nested field value",
944 },
945 }
946 }
947
948 impl_complete_builder! {
949 builder: TestBuilder,
950 config_field: config,
951 enable_methods: {
952 enable_feature => enable_field: EnabledFeature => "Enables a feature with default configuration",
953 }
954 }
955
956 #[test]
957 fn test_impl_complete_builder_nested_setter() {
958 let builder = TestBuilder::new().nested_field(42);
959
960 assert!(builder.get_config().nested_config.is_some());
961 let Some(nested) = builder.get_config().nested_config.as_ref() else {
962 panic!("expected nested_config to be Some");
963 };
964 assert_eq!(nested.nested_field, Some(42));
965 }
966
967 #[test]
968 fn test_impl_complete_builder_enable_method() {
969 let builder = TestBuilder::new().enable_feature();
970
971 assert!(builder.get_config().enable_field.is_some());
972 }
973
974 #[test]
975 fn test_impl_complete_builder_chaining() {
976 let builder = TestBuilder::new()
977 .simple_field("test".to_string())
978 .nested_field(123)
979 .enable_feature();
980
981 let config = builder.get_config();
982 assert_eq!(config.simple_field, Some("test".to_string()));
983 assert!(config.nested_config.is_some());
984 let Some(nested) = config.nested_config.as_ref() else {
985 panic!("expected nested_config to be Some");
986 };
987 assert_eq!(nested.nested_field, Some(123));
988 assert!(config.enable_field.is_some());
989 }
990}