nalgebra_macros/
lib.rs

1//! Macros for `nalgebra`.
2//!
3//! This crate is not intended for direct consumption. Instead, the macros are re-exported by
4//! `nalgebra` if the `macros` feature is enabled (enabled by default).
5
6#![deny(
7    nonstandard_style,
8    unused,
9    missing_docs,
10    rust_2018_idioms,
11    rust_2018_compatibility,
12    future_incompatible,
13    missing_copy_implementations,
14    missing_debug_implementations,
15    clippy::all
16)]
17
18mod matrix_vector_impl;
19mod stack_impl;
20
21use matrix_vector_impl::{Matrix, Vector};
22
23use crate::matrix_vector_impl::{dmatrix_impl, dvector_impl, matrix_impl, vector_impl};
24use proc_macro::TokenStream;
25use quote::quote;
26use stack_impl::stack_impl;
27use syn::parse_macro_input;
28
29/// Construct a fixed-size matrix directly from data.
30///
31/// **Note: Requires the `macros` feature to be enabled (enabled by default)**.
32///
33/// This macro facilitates easy construction of matrices when the entries of the matrix are known
34/// (either as constants or expressions). This macro produces an instance of `SMatrix`. This means
35/// that the data of the matrix is stored on the stack, and its dimensions are fixed at
36/// compile-time. If you want to construct a dynamic matrix, use [`dmatrix!`] instead.
37///
38/// `matrix!` is intended to be both the simplest and most efficient way to construct (small)
39/// matrices, and can also be used in *const fn* contexts.
40///
41/// The syntax is MATLAB-like. Column elements are separated by a comma (`,`), and a semi-colon
42/// (`;`) designates that a new row begins.
43///
44/// # Examples
45/// ```
46/// use nalgebra::matrix;
47///
48/// // Produces a Matrix3<_> == SMatrix<_, 3, 3>
49/// let a = matrix![1, 2, 3;
50///                 4, 5, 6;
51///                 7, 8, 9];
52/// ```
53///
54/// You can construct matrices with arbitrary expressions for its elements:
55///
56/// ```
57/// use nalgebra::{matrix, Matrix2};
58/// let theta = 0.45f64;
59///
60/// let r = matrix![theta.cos(), - theta.sin();
61///                 theta.sin(),   theta.cos()];
62/// ```
63#[proc_macro]
64pub fn matrix(stream: TokenStream) -> TokenStream {
65    matrix_impl(stream)
66}
67
68/// Construct a dynamic matrix directly from data.
69///
70/// **Note: Requires the `macros` feature to be enabled (enabled by default)**.
71///
72/// The syntax is exactly the same as for [`matrix!`], but instead of producing instances of
73/// `SMatrix`, it produces instances of `DMatrix`. At the moment it is not usable
74/// in `const fn` contexts.
75///
76/// # Example
77/// ```
78/// use nalgebra::dmatrix;
79///
80/// // Produces a DMatrix<_>
81/// let a = dmatrix![1, 2, 3;
82///                  4, 5, 6;
83///                  7, 8, 9];
84/// ```
85#[proc_macro]
86pub fn dmatrix(stream: TokenStream) -> TokenStream {
87    dmatrix_impl(stream)
88}
89
90/// Construct a fixed-size column vector directly from data.
91///
92/// **Note: Requires the `macros` feature to be enabled (enabled by default)**.
93///
94/// Similarly to [`matrix!`], this macro facilitates easy construction of fixed-size vectors.
95/// However, whereas the [`matrix!`] macro expects each row to be separated by a semi-colon,
96/// the syntax of this macro is instead similar to `vec!`, in that the elements of the vector
97/// are simply listed consecutively.
98///
99/// `vector!` is intended to be the most readable and performant way of constructing small,
100/// fixed-size vectors, and it is usable in `const fn` contexts.
101///
102/// # Example
103/// ```
104/// use nalgebra::vector;
105///
106/// // Produces a Vector3<_> == SVector<_, 3>
107/// let v = vector![1, 2, 3];
108/// ```
109#[proc_macro]
110pub fn vector(stream: TokenStream) -> TokenStream {
111    vector_impl(stream)
112}
113
114/// Construct a dynamic column vector directly from data.
115///
116/// **Note: Requires the `macros` feature to be enabled (enabled by default)**.
117///
118/// The syntax is exactly the same as for [`vector!`], but instead of producing instances of
119/// `SVector`, it produces instances of `DVector`. At the moment it is not usable
120/// in `const fn` contexts.
121///
122/// # Example
123/// ```
124/// use nalgebra::dvector;
125///
126/// // Produces a DVector<_>
127/// let v = dvector![1, 2, 3];
128/// ```
129#[proc_macro]
130pub fn dvector(stream: TokenStream) -> TokenStream {
131    dvector_impl(stream)
132}
133
134/// Construct a fixed-size point directly from data.
135///
136/// **Note: Requires the `macros` feature to be enabled (enabled by default)**.
137///
138/// Similarly to [`vector!`], this macro facilitates easy construction of points.
139///
140/// `point!` is intended to be the most readable and performant way of constructing small,
141/// points, and it is usable in `const fn` contexts.
142///
143/// # Example
144/// ```
145/// use nalgebra::point;
146///
147/// // Produces a Point3<_>
148/// let v = point![1, 2, 3];
149/// ```
150#[proc_macro]
151pub fn point(stream: TokenStream) -> TokenStream {
152    let vector = parse_macro_input!(stream as Vector);
153    let len = vector.len();
154    let array_tokens = vector.to_array_tokens();
155    let output = quote! {
156        nalgebra::Point::<_, #len> {
157            coords: nalgebra::SVector::<_, #len>
158                        ::from_array_storage(nalgebra::ArrayStorage([#array_tokens]))
159        }
160    };
161    proc_macro::TokenStream::from(output)
162}
163
164/// Construct a new matrix by stacking matrices in a block matrix.
165///
166/// **Note: Requires the `macros` feature to be enabled (enabled by default)**.
167///
168/// This macro facilitates the construction of
169/// [block matrices](https://en.wikipedia.org/wiki/Block_matrix)
170/// by stacking blocks (matrices) using the same MATLAB-like syntax as the [`matrix!`] and
171/// [`dmatrix!`] macros:
172///
173/// ```rust
174/// # use nalgebra::stack;
175/// #
176/// # fn main() {
177/// # let [a, b, c, d] = std::array::from_fn(|_| nalgebra::Matrix1::new(0));
178/// // a, b, c and d are matrices
179/// let block_matrix = stack![ a, b;
180///                            c, d ];
181/// # }
182/// ```
183///
184/// The resulting matrix is stack-allocated if the dimension of each block row and column
185/// can be determined at compile-time, otherwise it is heap-allocated.
186/// This is the case if, for every row, there is at least one matrix with a fixed number of rows,
187/// and, for every column, there is at least one matrix with a fixed number of columns.
188///
189/// [`stack!`] also supports special syntax to indicate zero blocks in a matrix:
190///
191/// ```rust
192/// # use nalgebra::stack;
193/// #
194/// # fn main() {
195/// # let [a, b, c, d] = std::array::from_fn(|_| nalgebra::Matrix1::new(0));
196/// // a and d are matrices
197/// let block_matrix = stack![ a, 0;
198///                            0, d ];
199/// # }
200/// ```
201/// Here, the `0` literal indicates a zero matrix of implicitly defined size.
202/// In order to infer the size of the zero blocks, there must be at least one matrix
203/// in every row and column of the matrix.
204/// In other words, no row or column can consist entirely of implicit zero blocks.
205///
206/// # Panics
207///
208/// Panics if dimensions are inconsistent and it cannot be determined at compile-time.
209///
210/// # Examples
211///
212/// ```
213/// use nalgebra::{matrix, SMatrix, stack};
214///
215/// let a = matrix![1, 2;
216///                 3, 4];
217/// let b = matrix![5, 6;
218///                 7, 8];
219/// let c = matrix![9, 10];
220///
221/// let block_matrix = stack![ a, b;
222///                            c, 0 ];
223///
224/// assert_eq!(block_matrix, matrix![1,  2,  5,  6;
225///                                  3,  4,  7,  8;
226///                                  9, 10,  0,  0]);
227///
228/// // Verify that the resulting block matrix is stack-allocated
229/// let _: SMatrix<_, 3, 4> = block_matrix;
230/// ```
231///
232/// The example above shows how stacking stack-allocated matrices results in a stack-allocated
233/// block matrix. If all row and column dimensions can not be determined at compile-time,
234/// the result is instead a dynamically allocated matrix:
235///
236/// ```
237/// use nalgebra::{dmatrix, DMatrix, Dyn, matrix, OMatrix, SMatrix, stack, U3};
238///
239/// # let a = matrix![1, 2; 3, 4]; let c = matrix![9, 10];
240/// // a and c as before, but b is a dynamic matrix this time
241/// let b = dmatrix![5, 6;
242///                  7, 8];
243///
244/// // In this case, the number of rows can be statically inferred to be 3 (U3),
245/// // but the number of columns cannot, hence it is dynamic
246/// let block_matrix: OMatrix<_, U3, Dyn> = stack![ a, b;
247///                                                 c, 0 ];
248///
249/// // If necessary, a fully dynamic matrix (DMatrix) can be obtained by reshaping
250/// let dyn_block_matrix: DMatrix<_> = block_matrix.reshape_generic(Dyn(3), Dyn(4));
251/// ```
252/// Note that explicitly annotating the types of `block_matrix` and `dyn_block_matrix` is
253/// only made for illustrative purposes, and is not generally necessary.
254///
255#[proc_macro]
256pub fn stack(stream: TokenStream) -> TokenStream {
257    let matrix = parse_macro_input!(stream as Matrix);
258    proc_macro::TokenStream::from(stack_impl(matrix).unwrap_or_else(syn::Error::into_compile_error))
259}