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]
218macro_rules! impl_complete_builder {
219 (
221 builder: $builder:ident,
222 config_field: $config_field:ident,
223 simple_setters: {
224 $($simple_field:ident: $simple_type:ty => $simple_doc:literal),* $(,)?
225 }
226 ) => {
227 impl $builder {
228 $(
229 #[doc = $simple_doc]
230 pub fn $simple_field(mut self, value: $simple_type) -> Self {
231 self.$config_field.$simple_field = Some(value);
232 self
233 }
234 )*
235 }
236 };
237
238 (
240 builder: $builder:ident,
241 config_field: $config_field:ident,
242 nested_setters: {
243 $($nested_path:ident: $nested_type:ty => {
244 $($nested_field:ident: $nested_field_type:ty => $nested_doc:literal),* $(,)?
245 }),* $(,)?
246 }
247 ) => {
248 impl $builder {
249 $($(
250 #[doc = $nested_doc]
251 pub fn $nested_field(mut self, value: $nested_field_type) -> Self {
252 $crate::with_nested!(self.$config_field.$nested_path, $nested_type, config => {
253 config.$nested_field = Some(value);
254 });
255 self
256 }
257 )*)*
258 }
259 };
260
261 (
263 builder: $builder:ident,
264 config_field: $config_field:ident,
265 enable_methods: {
266 $($enable_method:ident => $enable_field:ident: $enable_type:ty => $enable_doc:literal),* $(,)?
267 }
268 ) => {
269 impl $builder {
270 $(
271 #[doc = $enable_doc]
272 pub fn $enable_method(mut self) -> Self {
273 self.$config_field.$enable_field = Some(<$enable_type>::default());
274 self
275 }
276 )*
277 }
278 };
279}
280
281#[macro_export]
283macro_rules! impl_config_new_and_with_common {
284 (
285 $Config:ident,
286 common_defaults: ($model_name_opt:expr, $batch_size_opt:expr),
287 fields: { $( $field:ident : $default_expr:expr ),* $(,)? }
288 ) => {
289 impl $Config {
290 pub fn new() -> Self {
292 Self {
293 common: $crate::core::config::builder::ModelInferenceConfig::with_defaults(
294 $model_name_opt, $batch_size_opt
295 ),
296 $( $field: $default_expr ),*
297 }
298 }
299 pub fn with_common(common: $crate::core::config::builder::ModelInferenceConfig) -> Self {
301 Self {
302 common,
303 $( $field: $default_expr ),*
304 }
305 }
306 }
307 };
308}
309
310#[macro_export]
312macro_rules! impl_common_builder_methods {
313 ($Builder:ident, $common_field:ident) => {
314 impl $Builder {
315 pub fn model_path(mut self, model_path: impl Into<std::path::PathBuf>) -> Self {
317 self.$common_field = self.$common_field.model_path(model_path);
318 self
319 }
320 pub fn model_name(mut self, model_name: impl Into<String>) -> Self {
322 self.$common_field = self.$common_field.model_name(model_name);
323 self
324 }
325 pub fn batch_size(mut self, batch_size: usize) -> Self {
327 self.$common_field = self.$common_field.batch_size(batch_size);
328 self
329 }
330 pub fn enable_logging(mut self, enable: bool) -> Self {
332 self.$common_field = self.$common_field.enable_logging(enable);
333 self
334 }
335 pub fn ort_session(
337 mut self,
338 config: $crate::core::config::onnx::OrtSessionConfig,
339 ) -> Self {
340 self.$common_field = self.$common_field.ort_session(config);
341 self
342 }
343 }
344 };
345}
346
347#[macro_export]
351macro_rules! common_builder_methods {
352 ($common_field:ident) => {
353 pub fn model_path(mut self, model_path: impl Into<std::path::PathBuf>) -> Self {
355 self.$common_field = self.$common_field.model_path(model_path);
356 self
357 }
358 pub fn model_name(mut self, model_name: impl Into<String>) -> Self {
360 self.$common_field = self.$common_field.model_name(model_name);
361 self
362 }
363 pub fn batch_size(mut self, batch_size: usize) -> Self {
365 self.$common_field = self.$common_field.batch_size(batch_size);
366 self
367 }
368 pub fn enable_logging(mut self, enable: bool) -> Self {
370 self.$common_field = self.$common_field.enable_logging(enable);
371 self
372 }
373 pub fn ort_session(mut self, config: $crate::core::config::onnx::OrtSessionConfig) -> Self {
375 self.$common_field = self.$common_field.ort_session(config);
376 self
377 }
378 };
379}
380
381#[doc(hidden)]
395#[macro_export]
396macro_rules! __impl_adapter_builder_common {
397 (
398 builder_name: $Builder:ident,
399 adapter_name: $Adapter:ident,
400 config_type: $Config:ty,
401 adapter_type: $adapter_type_str:literal,
402 adapter_desc: $adapter_desc:literal,
403 task_type: $TaskType:ident,
404
405 fields: {
406 $($field_vis:vis $field_name:ident : $field_ty:ty = $field_default:expr),*
407 $(,)?
408 },
409
410 methods: {
411 $($method:item)*
412 }
413 ) => {
414 #[doc = $adapter_desc]
417 #[derive(Debug)]
418 pub struct $Builder {
419 config: $crate::domain::adapters::builder_config::AdapterBuilderConfig<$Config>,
421 $($field_vis $field_name : $field_ty),*
422 }
423
424 impl $Builder {
425 pub fn new() -> Self {
427 Self {
428 config: $crate::domain::adapters::builder_config::AdapterBuilderConfig::default(),
429 $($field_name : $field_default),*
430 }
431 }
432
433 pub fn base_adapter_info() -> $crate::core::traits::adapter::AdapterInfo {
438 $crate::core::traits::adapter::AdapterInfo::new(
439 $adapter_type_str,
440 $crate::core::traits::task::TaskType::$TaskType,
441 $adapter_desc,
442 )
443 }
444
445 $($method)*
447 }
448
449 impl Default for $Builder {
450 fn default() -> Self {
451 Self::new()
452 }
453 }
454
455 impl $crate::core::traits::OrtConfigurable for $Builder {
456 fn with_ort_config(mut self, config: $crate::core::config::OrtSessionConfig) -> Self {
457 self.config = self.config.with_ort_config(config);
458 self
459 }
460 }
461 };
462}
463
464#[macro_export]
514macro_rules! impl_adapter_builder {
515 (
517 builder_name: $Builder:ident,
518 adapter_name: $Adapter:ident,
519 config_type: $Config:ty,
520 adapter_type: $adapter_type_str:literal,
521 adapter_desc: $adapter_desc:literal,
522 task_type: $TaskType:ident,
523
524 fields: {
525 $($field_vis:vis $field_name:ident : $field_ty:ty = $field_default:expr),*
526 $(,)?
527 },
528
529 methods: {
530 $($method:item)*
531 }
532
533 build: $build_closure:expr,
534 ) => {
535 $crate::__impl_adapter_builder_common! {
537 builder_name: $Builder,
538 adapter_name: $Adapter,
539 config_type: $Config,
540 adapter_type: $adapter_type_str,
541 adapter_desc: $adapter_desc,
542 task_type: $TaskType,
543
544 fields: {
545 $($field_vis $field_name : $field_ty = $field_default),*
546 },
547
548 methods: {
549 pub fn with_config(mut self, config: $Config) -> Self {
551 self.config = self.config.with_task_config(config);
552 self
553 }
554
555 $($method)*
556 }
557 }
558
559 impl $crate::core::traits::adapter::AdapterBuilder for $Builder {
561 type Config = $Config;
562 type Adapter = $Adapter;
563
564 fn build(
565 self,
566 model_source: impl Into<$crate::core::ModelSource>,
567 ) -> Result<Self::Adapter, $crate::core::OCRError> {
568 let build_fn: fn(Self, $crate::core::ModelSource) -> Result<$Adapter, $crate::core::OCRError> = $build_closure;
569 build_fn(self, model_source.into())
570 }
571
572 fn with_config(mut self, config: Self::Config) -> Self {
573 self.config = self.config.with_task_config(config);
574 self
575 }
576
577 fn adapter_type(&self) -> &str {
578 $adapter_type_str
579 }
580 }
581 };
582
583 (
585 builder_name: $Builder:ident,
586 adapter_name: $Adapter:ident,
587 config_type: $Config:ty,
588 adapter_type: $adapter_type_str:literal,
589 adapter_desc: $adapter_desc:literal,
590 task_type: $TaskType:ident,
591
592 methods: {
593 $($method:item)*
594 }
595
596 build: $build_closure:expr,
597 ) => {
598 impl_adapter_builder! {
599 builder_name: $Builder,
600 adapter_name: $Adapter,
601 config_type: $Config,
602 adapter_type: $adapter_type_str,
603 adapter_desc: $adapter_desc,
604 task_type: $TaskType,
605
606 fields: {},
607
608 methods: {
609 $($method)*
610 }
611
612 build: $build_closure,
613 }
614 };
615
616 (
618 builder_name: $Builder:ident,
619 adapter_name: $Adapter:ident,
620 config_type: $Config:ty,
621 adapter_type: $adapter_type_str:literal,
622 adapter_desc: $adapter_desc:literal,
623 task_type: $TaskType:ident,
624
625 fields: {
626 $($field_vis:vis $field_name:ident : $field_ty:ty = $field_default:expr),*
627 $(,)?
628 }
629
630 build: $build_closure:expr,
631 ) => {
632 impl_adapter_builder! {
633 builder_name: $Builder,
634 adapter_name: $Adapter,
635 config_type: $Config,
636 adapter_type: $adapter_type_str,
637 adapter_desc: $adapter_desc,
638 task_type: $TaskType,
639
640 fields: {
641 $($field_vis $field_name : $field_ty = $field_default),*
642 },
643
644 methods: {}
645
646 build: $build_closure,
647 }
648 };
649
650 (
652 builder_name: $Builder:ident,
653 adapter_name: $Adapter:ident,
654 config_type: $Config:ty,
655 adapter_type: $adapter_type_str:literal,
656 adapter_desc: $adapter_desc:literal,
657 task_type: $TaskType:ident
658
659 build: $build_closure:expr,
660 ) => {
661 impl_adapter_builder! {
662 builder_name: $Builder,
663 adapter_name: $Adapter,
664 config_type: $Config,
665 adapter_type: $adapter_type_str,
666 adapter_desc: $adapter_desc,
667 task_type: $TaskType,
668
669 fields: {},
670
671 methods: {}
672
673 build: $build_closure,
674 }
675 };
676
677 (
679 builder_name: $Builder:ident,
680 adapter_name: $Adapter:ident,
681 config_type: $Config:ty,
682 adapter_type: $adapter_type_str:literal,
683 adapter_desc: $adapter_desc:literal,
684 task_type: $TaskType:ident,
685
686 fields: {
687 $($field_vis:vis $field_name:ident : $field_ty:ty = $field_default:expr),*
688 $(,)?
689 },
690
691 methods: {
692 $($method:item)*
693 }
694
695 overrides: {
696 with_config: $with_config_closure:expr,
697 adapter_type: $adapter_type_closure:expr,
698 }
699
700 build: $build_closure:expr,
701 ) => {
702 $crate::__impl_adapter_builder_common! {
704 builder_name: $Builder,
705 adapter_name: $Adapter,
706 config_type: $Config,
707 adapter_type: $adapter_type_str,
708 adapter_desc: $adapter_desc,
709 task_type: $TaskType,
710
711 fields: {
712 $($field_vis $field_name : $field_ty = $field_default),*
713 },
714
715 methods: {
716 $($method)*
717 }
718 }
719
720 impl $crate::core::traits::adapter::AdapterBuilder for $Builder {
722 type Config = $Config;
723 type Adapter = $Adapter;
724
725 fn build(
726 self,
727 model_source: impl Into<$crate::core::ModelSource>,
728 ) -> Result<Self::Adapter, $crate::core::OCRError> {
729 let build_fn: fn(Self, $crate::core::ModelSource) -> Result<$Adapter, $crate::core::OCRError> = $build_closure;
730 build_fn(self, model_source.into())
731 }
732
733 fn with_config(self, config: Self::Config) -> Self {
734 let with_config_fn: fn(Self, Self::Config) -> Self = $with_config_closure;
735 with_config_fn(self, config)
736 }
737
738 fn adapter_type(&self) -> &str {
739 let adapter_type_fn: fn(&Self) -> &str = $adapter_type_closure;
740 adapter_type_fn(self)
741 }
742 }
743 };
744
745 (
747 builder_name: $Builder:ident,
748 adapter_name: $Adapter:ident,
749 config_type: $Config:ty,
750 adapter_type: $adapter_type_str:literal,
751 adapter_desc: $adapter_desc:literal,
752 task_type: $TaskType:ident,
753
754 fields: {
755 $($field_vis:vis $field_name:ident : $field_ty:ty = $field_default:expr),*
756 $(,)?
757 },
758
759 methods: {
760 $($method:item)*
761 }
762
763 overrides: {
764 with_config: $with_config_closure:expr,
765 }
766
767 build: $build_closure:expr,
768 ) => {
769 $crate::__impl_adapter_builder_common! {
771 builder_name: $Builder,
772 adapter_name: $Adapter,
773 config_type: $Config,
774 adapter_type: $adapter_type_str,
775 adapter_desc: $adapter_desc,
776 task_type: $TaskType,
777
778 fields: {
779 $($field_vis $field_name : $field_ty = $field_default),*
780 },
781
782 methods: {
783 $($method)*
784 }
785 }
786
787 impl $crate::core::traits::adapter::AdapterBuilder for $Builder {
789 type Config = $Config;
790 type Adapter = $Adapter;
791
792 fn build(
793 self,
794 model_source: impl Into<$crate::core::ModelSource>,
795 ) -> Result<Self::Adapter, $crate::core::OCRError> {
796 let build_fn: fn(Self, $crate::core::ModelSource) -> Result<$Adapter, $crate::core::OCRError> = $build_closure;
797 build_fn(self, model_source.into())
798 }
799
800 fn with_config(self, config: Self::Config) -> Self {
801 let with_config_fn: fn(Self, Self::Config) -> Self = $with_config_closure;
802 with_config_fn(self, config)
803 }
804
805 fn adapter_type(&self) -> &str {
806 $adapter_type_str
807 }
808 }
809 };
810}
811
812#[macro_export]
838macro_rules! apply_ort_config {
839 ($builder:expr, $ort_config:expr) => {{
840 let builder = $builder;
841 if let Some(cfg) = $ort_config {
842 builder.with_ort_config(cfg)
843 } else {
844 builder
845 }
846 }};
847}
848
849#[cfg(test)]
850mod tests {
851
852 #[derive(Debug, Default)]
854 struct TestConfig {
855 simple_field: Option<String>,
856 nested_config: Option<NestedConfig>,
857 enable_field: Option<EnabledFeature>,
858 }
859
860 #[derive(Debug, Default)]
861 struct NestedConfig {
862 nested_field: Option<i32>,
863 }
864
865 impl NestedConfig {
866 fn new() -> Self {
867 Self::default()
868 }
869 }
870
871 #[derive(Debug, Default)]
872 struct EnabledFeature {
873 _enabled: bool,
874 }
875
876 #[derive(Debug)]
878 struct TestBuilder {
879 config: TestConfig,
880 }
881
882 impl TestBuilder {
883 fn new() -> Self {
884 Self {
885 config: TestConfig::default(),
886 }
887 }
888
889 fn get_config(&self) -> &TestConfig {
890 &self.config
891 }
892 }
893
894 impl_complete_builder! {
896 builder: TestBuilder,
897 config_field: config,
898 simple_setters: {
899 simple_field: String => "Sets a simple field value",
900 }
901 }
902
903 impl_complete_builder! {
904 builder: TestBuilder,
905 config_field: config,
906 nested_setters: {
907 nested_config: NestedConfig => {
908 nested_field: i32 => "Sets a nested field value",
909 },
910 }
911 }
912
913 impl_complete_builder! {
914 builder: TestBuilder,
915 config_field: config,
916 enable_methods: {
917 enable_feature => enable_field: EnabledFeature => "Enables a feature with default configuration",
918 }
919 }
920
921 #[test]
922 fn test_impl_complete_builder_nested_setter() {
923 let builder = TestBuilder::new().nested_field(42);
924
925 assert!(builder.get_config().nested_config.is_some());
926 let Some(nested) = builder.get_config().nested_config.as_ref() else {
927 panic!("expected nested_config to be Some");
928 };
929 assert_eq!(nested.nested_field, Some(42));
930 }
931
932 #[test]
933 fn test_impl_complete_builder_enable_method() {
934 let builder = TestBuilder::new().enable_feature();
935
936 assert!(builder.get_config().enable_field.is_some());
937 }
938
939 #[test]
940 fn test_impl_complete_builder_chaining() {
941 let builder = TestBuilder::new()
942 .simple_field("test".to_string())
943 .nested_field(123)
944 .enable_feature();
945
946 let config = builder.get_config();
947 assert_eq!(config.simple_field, Some("test".to_string()));
948 assert!(config.nested_config.is_some());
949 let Some(nested) = config.nested_config.as_ref() else {
950 panic!("expected nested_config to be Some");
951 };
952 assert_eq!(nested.nested_field, Some(123));
953 assert!(config.enable_field.is_some());
954 }
955}