1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
// Copyright (C) 2024-2025 Takayuki Sato. All Rights Reserved.
// This program is free software under MIT License.
// See the file LICENSE in this distribution for more details.
//! This crate provides attribute-like macros to override trait methods with other traits for
//! a structs or another trait.
//!
//! ## Install
//!
//! In `Cargo.toml`, write this crate as a dependency.
//!
//! ```toml
//! [dependencies]
//! override_macro = "0.1.1"
//! ```
//!
//! ## Usage
//!
//! First, by using `overridable` attribute-macro, collects trait information whose methods
//! override other trait's methods and are overridden with methods of other traits.
//!
//! The argument of this attribute-macro is to specify the module path.
//! This argument is optional but it is better to specify it because the trait name may be conflict
//! to other traits.
//!
//! Next, by using `override_with` attribute-macro, adds overridiing methods of the target trait
//! for a struct or a trait.
//!
//! The arguments of this attribute-macro are paths of traits having overriding methods.
//! This attribute-macro searches for methods with the same sigunature to the methods in the target
//! trait from the traits passed as the arguments, and then adds these method callings to the target
//! trait.
//!
//! ```rust
//! use override_macro::{overridable, override_with};
//!
//! #[overridable]
//! trait Trait0 {
//! fn method0(&self) -> bool;
//! fn method1(&self, b: bool) -> u64;
//! }
//!
//! mod module_a {
//! use override_macro::{overridable, override_with};
//!
//! #[overridable(mod = module_a)]
//! pub trait Trait1 {
//! fn method0(&self) -> bool { true }
//! }
//!
//! pub mod module_b {
//! use override_macro::{overridable, override_with};
//!
//! #[overridable(mod = module_a::module_b)]
//! pub trait Trait2 {
//! fn method1(&self, _b: bool) -> u64 { 123 }
//! }
//! }
//! }
//!
//! struct Struct0;
//! impl module_a::Trait1 for Struct0 {}
//! impl module_a::module_b::Trait2 for Struct0 {}
//!
//! #[override_with(module_a::Trait1, module_a::module_b::Trait2)]
//! impl Trait0 for Struct0 {
//! // The following method is added automatically by this attribute-macro
//! // fn method0(&self) -> bool {
//! // module_a::Trait1::method0(self)
//! // }
//! // fn method1(&self, _b: bool) -> u64 {
//! // module_a::module_b::Trait1::method1(self, _b)
//! // }
//! }
//! ```
use TokenStream;
/// Collects trait informations whose methods can override other trait methods, or can be overriden
/// with other trait methods.
///
/// This attribute-macro is attached to a trait definition block, and collects its name and its
/// method signatures.
/// The collected informations are used in `override_with` attribute-macro.
///
/// Internally, the trait information is managed using the trait name as the key, but there might
/// be other traits with the same name in different modules.
/// To treat such name conflicts, this macro can accept a module path as its arguments in the form
/// of `(mod module::path)`.
///
/// # Example
///
/// ```rust
/// use override_macro::overridable;
///
/// #[overridable]
/// trait TraitA {
/// /* ... */
/// }
///
/// #[overridable(mod = mod1::mod2)]
/// trait TraitB {
/// /* ... */
/// }
/// ```
/// Adds methods *overridden* methods with methods of other traits to the trait implementation.
///
/// This attribute-macro is attached to the `impl` block of the target trait for a struct or
/// another trait.
/// This searches for default implementations of methods with the same signature as the target
/// trait's methods from the traits specified in this macro's arguments.
/// And then, this adds method implementations to the `impl` block that call those default
/// implementations.
///
/// The target trait and the traits specified in the arguments of this attribute-macro must have
/// the `overridable` attribute-macro attached to their definition blocks.
///
/// If a method in the target trait has a default implemention, the overriding for the method
/// is skipped.
/// Therefore, if you want to implement a different process without overriding, or if multiple
/// traits in the attribute-macro arguments have the same method's default implementation,
/// you can directly implement it in the `impl` block.
///
/// # Example
///
/// ```rust
/// use override_macro::{overridable, override_with};
///
/// #[overridable]
/// trait Trait0 {
/// fn method0(&self, b: bool) { /* ... */ }
/// }
///
/// #[overridable]
/// trait Trait1 {
/// fn method1_a(&self, i: i32) { /* ... */ }
/// fn method1_b(&self, s: &str) { /* ... */ }
/// }
///
/// #[overridable]
/// trait Trait2 {
/// fn method0(&self, b: bool);
/// fn method1_a(&self, i: i32);
/// fn method1_b(&self, s: &str);
/// }
///
/// struct StructA;
/// impl Trait0 for StructA {}
/// impl Trait1 for StructA {}
///
/// #[override_with(Trait0, Trait1)]
/// impl Trait2 for StructA {
/// /* The following methods are automatically added by this attribute-macro.
/// fn method0(&self, b: bool) { Trait0::method0(self, b) }
/// fn method1_a(&self, i: i32) { Trait1::method1_a(self, i) }
/// */
/// // Skip to override method of which default implementation exists.
/// fn method1_b(&self, s: &str) { /* ... */ }
/// }
/// ```