Skip to main content

burn_core/module/param/
constant.rs

1use alloc::format;
2use burn_tensor::kind::{Autodiff, Basic};
3use core::fmt::Display;
4
5use crate as burn;
6use crate::module::{
7    Content, Devices, Module, ModuleDisplay, ModuleDisplayDefault, ModuleMapper, ModuleVisitor,
8};
9use burn_tensor::{Device, Tensor};
10
11/// Constant macro.
12#[macro_export]
13macro_rules! empty {
14    (module) => {
15        fn visit<V: burn::module::ModuleVisitor>(&self, _visitor: &mut V) {
16            // Nothing to do
17        }
18
19        fn map<M: burn::module::ModuleMapper>(self, _mapper: &mut M) -> Self {
20            self
21        }
22
23        fn to_device(self, _: &burn::tensor::Device) -> Self {
24            self
25        }
26
27        fn fork(self, _: &burn::tensor::Device) -> Self {
28            self
29        }
30
31        fn collect_devices(&self, devices: burn::module::Devices) -> burn::module::Devices {
32            devices
33        }
34
35        fn valid(&self) -> Self {
36            self.clone()
37        }
38
39        fn train(self) -> Self {
40            self
41        }
42    };
43
44    ($type:ty) => {
45        impl burn::module::Module for $type {
46            empty!(module);
47        }
48
49        impl burn::module::ModuleDisplayDefault for $type {
50            fn content(&self, content: burn::module::Content) -> Option<burn::module::Content> {
51                let string = format!("{}", self);
52                content.add_formatted(&string).optional()
53            }
54        }
55
56        impl burn::module::ModuleDisplay for $type {}
57    };
58}
59
60// TODO: breaking change for these constant types (currently empty record, non-persistent)?
61
62// General Types
63empty!(alloc::string::String);
64empty!(bool);
65
66// Float Types
67empty!(f64);
68empty!(f32);
69empty!(half::bf16);
70empty!(half::f16);
71
72// Unsigned Integer Types
73empty!(usize);
74empty!(u64);
75empty!(u32);
76empty!(u16);
77empty!(u8);
78
79// Signed Integer Types
80empty!(isize);
81empty!(i64);
82empty!(i32);
83empty!(i16);
84empty!(i8);
85
86impl burn::module::ModuleDisplay for str {}
87impl burn::module::ModuleDisplayDefault for str {
88    fn content(&self, content: burn::module::Content) -> Option<burn::module::Content> {
89        content.add_formatted(&self).optional()
90    }
91}
92
93// TODO: tensor record should persist
94impl<const D: usize, K: Autodiff> Module for Tensor<D, K> {
95    fn visit<V: ModuleVisitor>(&self, _visitor: &mut V) {}
96
97    fn map<M: ModuleMapper>(self, _mapper: &mut M) -> Self {
98        self
99    }
100
101    fn to_device(self, device: &Device) -> Self {
102        self.to_device(device)
103    }
104
105    fn fork(self, device: &Device) -> Self {
106        self.to_device(device)
107    }
108
109    fn collect_devices(&self, mut devices: Devices) -> Devices {
110        let device = self.device();
111
112        if !devices.contains(&device) {
113            devices.push(device)
114        }
115
116        devices
117    }
118
119    fn valid(&self) -> Self {
120        self.clone().without_autodiff()
121    }
122
123    fn train(self) -> Self {
124        Tensor::from_inner(self)
125    }
126}
127
128impl<const D: usize, K: Basic> ModuleDisplayDefault for Tensor<D, K> {
129    fn content(&self, content: Content) -> Option<Content> {
130        let string = format!("Tensor {{rank: {D}, shape: {:?}}}", self.shape().as_slice());
131        content.add_single(&string).optional()
132    }
133}
134
135impl<const D: usize, K: Basic> ModuleDisplay for Tensor<D, K> {}
136
137/// Container to satisfy the Module trait for types that are not modules.
138#[derive(Clone, Debug)]
139#[deprecated(
140    since = "0.21.0",
141    note = "Ignored<T> is deprecated. Use #[module(skip)] for non-persistent fields (same behavior)."
142)]
143pub struct Ignored<T>(pub T);
144
145#[allow(deprecated)]
146impl<T> Module for Ignored<T>
147where
148    T: Sync + Send + core::fmt::Debug + Clone,
149{
150    fn visit<V: ModuleVisitor>(&self, _visitor: &mut V) {
151        // Nothing to do
152    }
153
154    fn map<M: ModuleMapper>(self, _mapper: &mut M) -> Self {
155        self
156    }
157
158    fn to_device(self, _: &Device) -> Self {
159        self
160    }
161
162    fn fork(self, _: &Device) -> Self {
163        self
164    }
165
166    fn collect_devices(&self, devices: Devices) -> Devices {
167        devices
168    }
169
170    fn valid(&self) -> Self {
171        self.clone()
172    }
173
174    fn train(self) -> Self {
175        self
176    }
177}
178
179#[allow(deprecated)]
180impl<T> ModuleDisplayDefault for Ignored<T>
181where
182    T: Sync + Send + core::fmt::Debug + Clone,
183{
184    fn content(&self, content: Content) -> Option<Content> {
185        // For now, just print the debug representation of the ignored value
186        content.add_single(&format!("{:?}", self.0)).optional()
187    }
188}
189
190#[allow(deprecated)]
191impl<T> ModuleDisplay for Ignored<T> where T: Sync + Send + core::fmt::Debug + Clone {}
192
193#[allow(deprecated)]
194impl<T> Display for Ignored<T>
195where
196    T: Sync + Send + core::fmt::Debug + Clone,
197{
198    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
199        write!(f, "{:?}", self.0)
200    }
201}
202
203#[allow(deprecated)]
204// Implement deref for Ignored
205impl<T> core::ops::Deref for Ignored<T> {
206    type Target = T;
207
208    fn deref(&self) -> &Self::Target {
209        &self.0
210    }
211}
212
213#[cfg(all(test, feature = "std"))]
214mod tests {
215    use core::marker::PhantomData;
216
217    use burn::module::Module;
218
219    use crate as burn;
220
221    #[test]
222    fn empty_module_with_phantom() {
223        #[derive(Module, Debug, new)]
224        struct EmptyModule<T: core::fmt::Debug + Clone + Send> {
225            #[module(skip)]
226            _phantom: PhantomData<T>,
227        }
228
229        let _module = EmptyModule::<bool>::new();
230
231        assert_eq!(core::mem::size_of::<EmptyModule<bool>>(), 0);
232    }
233}