kas_macros/lib.rs
1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License in the LICENSE-APACHE file or at:
4// https://www.apache.org/licenses/LICENSE-2.0
5
6//! KAS macros
7//!
8//! This crate extends [`impl-tools`](https://docs.rs/impl-tools/).
9
10extern crate proc_macro;
11
12use impl_tools_lib::{anon, autoimpl, scope};
13use proc_macro::TokenStream;
14use proc_macro_error2::{emit_call_site_error, emit_error, proc_macro_error};
15use syn::parse_macro_input;
16use syn::spanned::Spanned;
17
18mod collection;
19mod extends;
20mod make_layout;
21mod parser;
22mod scroll_traits;
23mod visitors;
24mod widget;
25mod widget_args;
26mod widget_derive;
27
28/// Implement `Default`
29///
30/// See [`impl_tools::impl_default`](https://docs.rs/impl-tools/latest/impl_tools/attr.impl_default.html)
31/// for full documentation.
32#[proc_macro_attribute]
33#[proc_macro_error]
34pub fn impl_default(attr: TokenStream, item: TokenStream) -> TokenStream {
35 let mut toks = item.clone();
36 match syn::parse::<impl_tools_lib::ImplDefault>(attr) {
37 Ok(attr) => toks.extend(TokenStream::from(attr.expand(item.into()))),
38 Err(err) => {
39 emit_call_site_error!(err);
40 // Since this form of invocation only adds implementations, we can
41 // safely output the original item, thus reducing secondary errors.
42 }
43 }
44 toks
45}
46
47/// A variant of the standard `derive` macro
48///
49/// See [`impl_tools::autoimpl`](https://docs.rs/impl-tools/latest/impl_tools/attr.autoimpl.html)
50/// for full documentation.
51///
52/// The following traits are supported:
53///
54/// | Path | *ignore* | *using* | *notes* |
55/// |----- |--- |--- |--- |
56/// | [`::core::borrow::Borrow<T>`] | - | borrow target | `T` is type of target field |
57/// | [`::core::borrow::BorrowMut<T>`] | - | borrow target | `T` is type of target field |
58/// | [`::core::clone::Clone`] | yes | - | ignored fields use `Default::default()` |
59/// | [`::core::cmp::Eq`] | * | - | *allowed with `PartialEq` |
60/// | [`::core::cmp::Ord`] | yes | - | |
61/// | [`::core::cmp::PartialEq`] | yes | - | |
62/// | [`::core::cmp::PartialOrd`] | yes | - | |
63/// | [`::core::convert::AsRef<T>`] | - | ref target | `T` is type of target field |
64/// | [`::core::convert::AsMut<T>`] | - | ref target | `T` is type of target field |
65/// | [`::core::default::Default`] | - | - | [`macro@impl_default`] is a more flexible alternative |
66/// | [`::core::fmt::Debug`] | yes | - | |
67/// | [`::core::hash::Hash`] | yes | - | |
68/// | [`::core::marker::Copy`] | * | - | *allowed with `Clone` |
69/// | [`::core::ops::Deref`] | - | deref target | `type Target` is type of target field |
70/// | [`::core::ops::DerefMut`] | - | deref target | `type Target` is type of target field |
71#[proc_macro_attribute]
72#[proc_macro_error]
73pub fn autoimpl(attr: TokenStream, item: TokenStream) -> TokenStream {
74 use autoimpl::ImplTrait;
75 use scroll_traits::ImplViewport;
76 use std::iter::once;
77
78 let mut toks = item.clone();
79 match syn::parse::<autoimpl::Attr>(attr) {
80 Ok(autoimpl::Attr::ForDeref(ai)) => toks.extend(TokenStream::from(ai.expand(item.into()))),
81 Ok(autoimpl::Attr::ImplTraits(ai)) => {
82 // We could use lazy_static to construct a HashMap for fast lookups,
83 // but given the small number of impls a "linear map" is fine.
84 let find_impl = |path: &syn::Path| {
85 autoimpl::STD_IMPLS
86 .iter()
87 .cloned()
88 .chain(once(&ImplViewport as &dyn ImplTrait))
89 .find(|impl_| impl_.path().matches_ident_or_path(path))
90 };
91 toks.extend(TokenStream::from(ai.expand(item.into(), find_impl)))
92 }
93 Err(err) => {
94 emit_call_site_error!(err);
95 // Since autoimpl only adds implementations, we can safely output
96 // the original item, thus reducing secondary errors.
97 }
98 }
99 toks
100}
101
102const IMPL_SCOPE_RULES: [&dyn scope::ScopeAttr; 3] = [
103 &scope::AttrImplDefault,
104 &widget_args::AttrImplWidget,
105 &widget_derive::AttrDeriveWidget,
106];
107
108fn find_attr(path: &syn::Path) -> Option<&'static dyn scope::ScopeAttr> {
109 IMPL_SCOPE_RULES
110 .iter()
111 .cloned()
112 .find(|rule| rule.path().matches(path))
113}
114
115/// Scope supporting `impl Self` and advanced attribute macros
116///
117/// This macro facilitates definition of a type (struct, enum or union) plus
118/// implementations via `impl Self { .. }` syntax: `Self` is expanded to the
119/// type's name, including generics and bounds (as defined on the type).
120///
121/// Caveat: `rustfmt` can not yet format contents (see
122/// [rustfmt#5254](https://github.com/rust-lang/rustfmt/issues/5254),
123/// [rustfmt#5538](https://github.com/rust-lang/rustfmt/pull/5538)).
124///
125/// Note: prefer [`macro@impl_self`] over this macro unless using
126/// [`macro@impl_default`]. This macro will be removed once
127/// [RFC 3681](https://github.com/rust-lang/rfcs/pull/3681) (default field
128/// values) is stable in this crate's MSRV.
129///
130/// See [`impl_tools::impl_scope`](https://docs.rs/impl-tools/latest/impl_tools/macro.impl_scope.html)
131/// for full documentation.
132///
133/// ## Special attribute macros
134///
135/// Additionally, `impl_scope!` supports special attribute macros evaluated
136/// within its scope:
137///
138/// - [`#[impl_default]`](macro@impl_default): implement [`Default`] using
139/// field initializers (which are not legal syntax outside of `impl_scope!`)
140/// - [`#[widget]`](macro@widget): implement `kas::Widget` trait family
141///
142/// Note: matching these macros within `impl_scope!` does not use path
143/// resolution. Using `#[kas_macros::impl_default]` would resolve the variant
144/// of this macro which *doesn't support* field initializers.
145#[proc_macro_error]
146#[proc_macro]
147pub fn impl_scope(input: TokenStream) -> TokenStream {
148 let mut scope = parse_macro_input!(input as scope::Scope);
149 scope.apply_attrs(find_attr);
150 scope.expand().into()
151}
152
153fn find_impl_self_attrs(path: &syn::Path) -> Option<&'static dyn scope::ScopeAttr> {
154 use scope::ScopeAttr;
155 if widget_args::AttrImplWidget.path().matches(path) {
156 Some(&widget_args::AttrImplWidget)
157 } else if widget_derive::AttrDeriveWidget.path().matches(path) {
158 Some(&widget_derive::AttrDeriveWidget)
159 } else {
160 None
161 }
162}
163
164/// Implement a type with `impl Self` syntax
165///
166/// This attribute macro supports a type (struct, enum, type alias or union)
167/// definition plus associated `impl` items within a `mod`.
168///
169/// Macro expansion discards the `mod` entirely, placing all contents into the
170/// outer scope. This simplifies privacy rules in many use-cases, and highlights
171/// that the usage of `mod` is purely a hack to make the macro input valid Rust
172/// syntax (and thus compatible with `rustfmt`).
173///
174/// ## Special attribute macros
175///
176/// Additionally, `#[impl_self]` supports special attribute macros evaluated
177/// within its scope:
178///
179/// - [`#[widget]`](macro@widget): implement `kas::Widget` trait family
180///
181/// ## Syntax
182///
183/// > _ImplSelf_ :\
184/// > `#[impl_self]` `mod` _Name_ `{` _ScopeItem_ _ItemImpl_ * `}`
185/// >
186/// > _ScopeItem_ :\
187/// > _ItemEnum_ | _ItemStruct_ | _ItemType_ | _ItemUnion_
188///
189/// Here, _ItemEnum_, _ItemStruct_, _ItemType_ and _ItemUnion_ are `enum`,
190/// `struct`, `type` alias and `union` definitions respectively. Whichever of
191/// these is used, it must match the module name _Name_.
192///
193/// _ItemImpl_ is an `impl` item. It may use the standard implementation syntax
194/// (e.g. `impl Debug for MyType { .. }`) or `impl Self` syntax (see below).
195///
196/// The `mod` may not contain any other items, except `doc` items (documentation
197/// on the module itself is ignored in favour of documentation on the defined
198/// type) and attributes (which apply as usual).
199///
200/// ### `impl Self` syntax
201///
202/// `impl Self` "syntax" is syntactically-valid (but not semantically-valid)
203/// Rust syntax for writing inherent and trait `impl` blocks:
204///
205/// - `impl Self { ... }` — an inherent `impl` item on the defined type
206/// - `impl Debug for Self { ... }` — a trait `impl` item on the defined type
207///
208/// Generic parameters and bounds are copied from the type definition.
209/// Additional generic parameters may be specified; these extend the list of
210/// generic parameters on the type itself, and thus must have distinct names.
211/// Additional bounds (where clauses) may be specified; these extend the list of
212/// bounds on the type itself.
213///
214/// ## Example
215///
216/// ```
217/// #[kas_macros::impl_self]
218/// mod Pair {
219/// /// A pair of values of type `T`
220/// pub struct Pair<T>(T, T);
221///
222/// impl Self {
223/// pub fn new(a: T, b: T) -> Self {
224/// Pair(a, b)
225/// }
226/// }
227///
228/// impl Self where T: Clone {
229/// pub fn splat(a: T) -> Self {
230/// let b = a.clone();
231/// Pair(a, b)
232/// }
233/// }
234/// }
235/// ```
236#[proc_macro_attribute]
237#[proc_macro_error]
238pub fn impl_self(attr: TokenStream, input: TokenStream) -> TokenStream {
239 let _ = parse_macro_input!(attr as scope::ScopeModAttrs);
240 let mut scope = parse_macro_input!(input as scope::ScopeMod).contents;
241 scope.apply_attrs(find_impl_self_attrs);
242 scope.expand().into()
243}
244
245/// Attribute to implement the `kas::Widget` family of traits
246///
247/// This may *only* be used within the [`macro@impl_self`], [`impl_scope!`]
248/// and [`impl_anon!`] macros. It does not need to be imported (it is resolved
249/// by the afore-mentioned macros).
250///
251/// Assists implementation of the [`Widget`], [`Events`], [`Layout`] and [`Tile`] traits.
252/// Implementations of these traits are generated if missing or augmented with
253/// missing method implementations.
254///
255/// This macro may inject methods into existing [`Layout`] / [`Tile`] /
256/// [`Events`] / [`Widget`] implementations.
257/// (In the case of multiple implementations of the same trait, as used for
258/// specialization, only the first implementation of each trait is extended.)
259///
260/// See also the [`macro@layout`] attribute which assists in implementing
261/// [`Layout`].
262///
263/// ## Fields
264///
265/// The struct must contain a field of type `widget_core!()` (usually named
266/// `core`). The macro `widget_core!()` is a placeholder, expanded by
267/// `#[widget]` and used to identify the field used (any name may be used).
268/// This type implements [`Default`] and [`Clone`], though the clone is not an
269/// exact clone (cloned widgets must still be configured).
270///
271/// Assuming the deriving type is a `struct` or `tuple struct`, fields support
272/// the following attributes:
273///
274/// - `#[widget]`: marks the field as a [`Widget`] to be configured, enumerated by
275/// [`Widget::get_child`] and included by glob layouts
276/// - `#[widget(expr)]`: the same, but maps the data reference type; `expr` is
277/// an expression returning a reference to the child widget's input data;
278/// available inputs are `self`, `data` (own input data) and `index`
279/// (of the child).
280/// - `#[widget = expr]`: an alternative way of writing the above
281/// - `#[collection]`: the field is a [`Collection`] of widgets
282///
283/// ## Examples
284///
285/// A simple example is the
286/// [`Frame`](https://docs.rs/kas/latest/kas/widgets/struct.Frame.html) widget:
287///
288/// ```ignore
289/// #[impl_self]
290/// mod Frame {
291/// /// A frame around content
292/// #[derive(Clone, Default)]
293/// #[widget]
294/// #[layout(frame!(self.inner))]
295/// pub struct Frame<W: Widget> {
296/// core: widget_core!(),
297/// #[widget]
298/// pub inner: W,
299/// }
300///
301/// impl Self {
302/// /// Construct a frame
303/// #[inline]
304/// pub fn new(inner: W) -> Self {
305/// Frame {
306/// core: Default::default(),
307/// inner,
308/// }
309/// }
310/// }
311/// }
312/// ```
313///
314/// ## Method modification
315///
316/// As a policy, this macro *may* inject code into user-defined methods of
317/// `Widget` and its super traits, such that:
318///
319/// - The modification cannot have harmful side effects (other than reported
320/// errors).
321/// - All side effects observable outside of reported error cases must be
322/// documented in the widget method documentation.
323///
324/// As an example, status checks are injected into some `Layout` methods to
325/// enforce the expected call order of methods at runtime in debug builds.
326///
327/// ## Debugging
328///
329/// To inspect the output of this macro, set the environment variable
330/// `KAS_DEBUG_WIDGET` to the name of the widget concerned, dump the output to
331/// a temporary file and format. For example:
332/// ```sh
333/// KAS_DEBUG_WIDGET=Border cargo build > temp.rs
334/// rustfmt temp.rs
335/// ```
336///
337/// [`Widget`]: https://docs.rs/kas/latest/kas/trait.Widget.html
338/// [`Widget::get_child`]: https://docs.rs/kas/latest/kas/trait.Widget.html#method.get_child
339/// [`Layout`]: https://docs.rs/kas/latest/kas/trait.Layout.html
340/// [`Tile`]: https://docs.rs/kas/latest/kas/trait.Tile.html
341/// [`Events`]: https://docs.rs/kas/latest/kas/trait.Events.html
342/// [`Collection`]: https://docs.rs/kas/latest/kas/trait.Collection.html
343#[proc_macro_attribute]
344#[proc_macro_error]
345pub fn widget(_: TokenStream, item: TokenStream) -> TokenStream {
346 emit_call_site_error!("must be used within scope of #[impl_self], impl_scope! or impl_anon!");
347 item
348}
349
350/// Provide a default implementation of the [`Layout`] trait for a widget
351///
352/// This attribute macro may be used with the [`macro@widget`] macro to provide
353/// an implementation of [`Layout`].
354///
355/// The `#[layout]` attribute **must** follow the [`macro@widget`] attribute (it
356/// is not a stand-alone macro).
357/// It does not need to be imported (it is resolved by [`macro@widget`]).
358///
359/// ## Overriding provided fns
360///
361/// This macro implements [`MacroDefinedLayout`] for the widget and adjusts the
362/// default implementations of each [`Layout`] method to call the corresponding
363/// [`MacroDefinedLayout`] method. The user may instead provide a direct
364/// implementation of any [`Layout`] method; this implementation may or may not
365/// call the corresponding [`MacroDefinedLayout`] method.
366///
367/// ## Layout syntax
368///
369/// Syntax is as follows:
370///
371/// > _Item_: _MemberItem_ _Call_* | _LitItem_ _Call_* |
372/// > _MacroItem_ _Call_* | _ExprItem_\
373/// > A single item
374/// >
375/// > _MemberItem_: `self` `.` _Member_\
376/// > A reference to a field (e.g. `self.label` or `self.0`); this
377/// > field must be a `#[widget]`.
378/// >
379/// > _LitItem_: _StrLit_\
380/// > A string literal (e.g. `"Hello world"`). This implicitly
381/// > constructs a widget roughly equivalent to `Label<'static str>` but without
382/// > text wrapping.
383/// >
384/// > _MacroItem_: (`frame` | `column` | `row` | `list` | `float` |
385/// > `grid`) `!` _MacroArgs_\
386/// > These layout macros are natively supported in layout syntax.
387/// > They are equivalent to the like-named [macros in `kas::widgets`] aside from
388/// > name resolution.
389/// >
390/// > _ExprItem_: _Expr_\
391/// > An expression yielding a widget, e.g.
392/// > `Label::new("Hello world")`. The result must be an object of some type
393/// > `W: Widget<Data = ()>`. This widget will be stored in a hidden field and
394/// > is accessible through `Tile::get_child` but does not receive input data.
395///
396/// > _Call_ : (`.` ([`align`] | [`pack`] | [`with_stretch`] | [`with_margin_style`]) _MethodArgs_)\
397/// > A method call modifying layout.
398///
399/// [`Layout`]: https://docs.rs/kas/latest/kas/trait.Layout.html
400/// [`MacroDefinedLayout`]: https://docs.rs/kas/latest/kas/trait.MacroDefinedLayout.html
401/// [macros in `kas::widgets`]: https://docs.rs/kas/latest/kas/widgets/#macros
402/// [`align`]: https://docs.rs/kas/latest/kas/widgets/adapt/trait.AdaptWidget.html#method.align
403/// [`pack`]: https://docs.rs/kas/latest/kas/widgets/adapt/trait.AdaptWidget.html#method.pack
404/// [`with_stretch`]: https://docs.rs/kas/latest/kas/widgets/adapt/trait.AdaptWidget.html#method.with_stretch
405/// [`with_margin_style`]: https://docs.rs/kas/latest/kas/widgets/adapt/trait.AdaptWidget.html#method.with_margin_style
406#[proc_macro_attribute]
407#[proc_macro_error]
408pub fn layout(_: TokenStream, item: TokenStream) -> TokenStream {
409 emit_call_site_error!("must follow use of #[widget]");
410 item
411}
412
413/// Derive the [`Widget`] family of traits
414///
415/// This may *only* be used within the [`macro@impl_self`], [`impl_scope!`]
416/// and [`impl_anon!`] macros.
417///
418/// This macro derives a [`Widget`] implementation from the inner field
419/// annotated with `#[widget]`. The deriving type may (optionally) override:
420///
421/// - Any [`Layout`] method
422/// - A subset of [`Tile`] methods: `navigable`, `tooltip`, `role`, `role_child_properties`, `try_probe`, `nav_next`
423/// - The `Data` type (see [the example below](#example-mapping-data))
424///
425/// ## Example
426///
427/// ```ignore
428/// #[impl_self]
429/// mod Align {
430/// /// Apply an alignment hint
431/// #[derive_widget]
432/// pub struct Align<W: Widget> {
433/// #[widget]
434/// pub inner: W,
435/// hints: AlignHints,
436/// }
437///
438/// impl Self {
439/// /// Construct
440/// #[inline]
441/// pub fn new(inner: W, hints: AlignHints) -> Self {
442/// Align { inner, hints }
443/// }
444/// }
445///
446/// impl Layout for Self {
447/// fn set_rect(&mut self, cx: &mut SizeCx, rect: Rect, hints: AlignHints) {
448/// self.inner.set_rect(cx, rect, self.hints.combine(hints));
449/// }
450/// }
451/// }
452/// ```
453///
454/// ### Example mapping data
455///
456/// This macro supports mapping the data passed to the inner widget. The
457/// attribute annotating the inner field specifies the data map. It is required
458/// to specify the `Widget::Data` type.
459///
460/// ```ignore
461/// #[impl_self]
462/// mod Map {
463/// #[autoimpl(Deref, DerefMut using self.inner)]
464/// #[autoimpl(Viewport using self.inner where W: trait)]
465/// #[derive_widget]
466/// pub struct Map<A, W: Widget, F>
467/// where
468/// F: for<'a> Fn(&'a A) -> &'a W::Data,
469/// {
470/// #[widget = (self.map_fn)(data)]
471/// pub inner: W,
472/// map_fn: F,
473/// _data: PhantomData<A>,
474/// }
475///
476/// impl Widget for Self {
477/// type Data = A;
478/// }
479/// }
480/// ```
481///
482/// ### A note on `Deref`
483///
484/// The above examples implement [`Deref`] over the inner widget. This is
485/// acceptable for a simple wrapping "derive widget". It is not recommended to
486/// implement [`Deref`] for non-derived widgets (i.e. when the outer widget has
487/// its own `Id`) due to the potential for method collision (e.g. `outer.id()`
488/// may resolve to `outer.deref().id()` when the trait providing `fn id` is not
489/// in scope, yet is available through a bound on the field).
490///
491/// [`Layout`]: https://docs.rs/kas/latest/kas/trait.Layout.html
492/// [`Tile`]: https://docs.rs/kas/latest/kas/trait.Tile.html
493/// [`Widget`]: https://docs.rs/kas/latest/kas/trait.Widget.html
494/// [`Deref`]: std::ops::Deref
495#[proc_macro_attribute]
496#[proc_macro_error]
497pub fn derive_widget(_: TokenStream, item: TokenStream) -> TokenStream {
498 emit_call_site_error!("must be used within scope of #[impl_self], impl_scope! or impl_anon!");
499 item
500}
501
502/// Construct a single-instance struct
503///
504/// Rust doesn't currently support [`impl Trait { ... }` expressions](https://github.com/canndrew/rfcs/blob/impl-trait-expressions/text/0000-impl-trait-expressions.md)
505/// or implicit typing of struct fields. This macro is a **hack** allowing that.
506///
507/// Example:
508/// ```
509/// # use kas_macros as kas;
510/// use std::fmt;
511/// fn main() {
512/// let world = "world";
513/// let says_hello_world = kas::impl_anon! {
514/// struct(&'static str = world);
515/// impl fmt::Display for Self {
516/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
517/// write!(f, "hello {}", self.0)
518/// }
519/// }
520/// };
521/// assert_eq!(format!("{}", says_hello_world), "hello world");
522/// }
523/// ```
524///
525/// That is, this macro creates an anonymous struct type (must be a struct),
526/// which may have trait implementations, then creates an instance of that
527/// struct.
528///
529/// Struct fields may have a fixed type or may be generic. Syntax is as follows:
530///
531/// - **regular struct:** `ident: ty = value`
532/// - **regular struct:** `ident: ty` (uses `Default` to construct value)
533/// - **tuple struct:** `ty = value`
534/// - **tuple struct:** `ty` (uses `Default` to construct value)
535///
536/// The field name, `ident`, may be `_` (anonymous field).
537///
538/// Refer to [examples](https://github.com/search?q=impl_anon+repo%3Akas-gui%2Fkas+path%3Aexamples&type=Code) for usage.
539#[proc_macro_error]
540#[proc_macro]
541pub fn impl_anon(input: TokenStream) -> TokenStream {
542 let mut input = parse_macro_input!(input as anon::Anon);
543 for field in input.fields.iter_mut() {
544 if matches!(&field.ty, syn::Type::Infer(_)) {
545 let span = if let Some(ref ident) = field.ident {
546 ident.span()
547 } else if let Some((ref eq, _)) = field.assignment {
548 eq.span()
549 } else {
550 // This is always available and should be the first choice,
551 // but it may be synthesized (thus no useful span).
552 // We can't test since Span::eq is unstable!
553 field.ty.span()
554 };
555 emit_error!(span, "expected `: TYPE`");
556 }
557 }
558 let mut scope = input.into_scope();
559 scope.apply_attrs(find_attr);
560 scope.expand().into()
561}
562
563/// Index of a child widget
564///
565/// This macro is usable only within an [`macro@impl_self`], [`impl_scope!`] or
566/// [`impl_anon!`] macro using the [`macro@widget`] attribute.
567///
568/// Example usage: `widget_index![self.a]`. If `a` is a child widget (a field
569/// marked with the `#[widget]` attribute), then this expands to the child
570/// widget's index (as used by [`Widget::get_child`]). Otherwise, this is an error.
571///
572/// [`Widget::get_child`]: https://docs.rs/kas/latest/kas/trait.Widget.html#method.get_child
573#[proc_macro_error]
574#[proc_macro]
575pub fn widget_index(input: TokenStream) -> TokenStream {
576 let input = parse_macro_input!(input as visitors::UnscopedInput);
577 input.into_token_stream().into()
578}
579
580/// Generate an anonymous struct which implements [`kas::Collection`]
581///
582/// # Syntax
583///
584/// > _Collection_ :\
585/// > `collection!` `[` _Items_<sup>\?</sup> `]`
586/// >
587/// > _Items_ :\
588/// > (_Item_ `,`)<sup>\*</sup> _Item_ `,`<sup>\?</sup>
589///
590/// In this case, _Item_ may be:
591///
592/// - A string literal (interpreted as a label widget), optionally followed by
593/// any of the following method calls: [`align`], [`pack`],
594/// [`with_stretch`], [`with_margin_style`]
595/// - An expression yielding an object implementing `Widget<Data = _A>`
596///
597/// In case all _Item_ instances are a string literal, the data type of the
598/// `collection!` widget will be `()`; otherwise the data type of the widget is `_A`
599/// where `_A` is a generic type parameter of the widget.
600///
601/// For example usage, see [`List`](https://docs.rs/kas/latest/kas/widgets/struct.List.html).
602///
603/// [`kas::Collection`]: https://docs.rs/kas/latest/kas/trait.Collection.html
604/// [`align`]: https://docs.rs/kas/latest/kas/widgets/adapt/trait.AdaptWidget.html#method.align
605/// [`pack`]: https://docs.rs/kas/latest/kas/widgets/adapt/trait.AdaptWidget.html#method.pack
606/// [`with_stretch`]: https://docs.rs/kas/latest/kas/widgets/adapt/trait.AdaptWidget.html#method.with_stretch
607/// [`with_margin_style`]: https://docs.rs/kas/latest/kas/widgets/adapt/trait.AdaptWidget.html#method.with_margin_style
608#[proc_macro_error]
609#[proc_macro]
610pub fn collection(input: TokenStream) -> TokenStream {
611 parse_macro_input!(input as collection::Collection)
612 .expand()
613 .into()
614}
615
616/// Generate an anonymous struct which implements [`kas::CellCollection`]
617///
618/// # Syntax
619///
620/// > _Collection_ :\
621/// > `cell_collection!` `{` _ItemArms_<sup>\?</sup> `}`
622/// >
623/// > _ItemArms_ :\
624/// > (_ItemArm_ `,`)<sup>\*</sup> _ItemArm_ `,`<sup>\?</sup>
625/// >
626/// > _ItemArm_ :\
627/// > _Cell_ | _RowMacro_ | _ColumnMacro_
628/// >
629/// > _Cell_ :\
630/// > `(` _Column_ `,` _Row_ `)` `=>` _Item_
631/// >
632/// > _Column_, _Row_ :\
633/// > _LitInt_ | ( _LitInt_ `..=` _LitInt_ )
634/// >
635/// > _RowMacro_ :\
636/// > &npsb; `row!` `[` (_Item_ `,` | `_` `,`)* _Item_ `]`
637/// >
638/// > _ColumnMacro_ :\
639/// > &npsb; `column!` `[` (_Item_ `,` | `_` `,`)* _Item_ `]`
640///
641/// Here, _Column_ and _Row_ are selected via an index (from 0) or an inclusive
642/// range, for example `2` or `2..=3`.
643///
644/// A `row!` macro resolves to a list of cells whose column index is one larger
645/// than maximum prior column index and whose row indices count from 0.
646/// As a special case, `_` may be used to skip a cell (infer an empty cell).
647/// A `column!` macro functions similarly.
648///
649/// _Item_ may be:
650///
651/// - A string literal (interpreted as a label widget), optionally followed by
652/// any of the following method calls: [`align`], [`pack`], [`with_stretch`]
653/// [`with_stretch`], [`with_margin_style`]
654/// - An expression yielding an object implementing `Widget<Data = _A>`
655///
656/// In case all _Item_ instances are a string literal, the data type of the
657/// `collection!` widget will be `()`; otherwise the data type of the widget is `_A`
658/// where `_A` is a generic type parameter of the widget.
659///
660/// For example usage, see [`Grid`](https://docs.rs/kas/latest/kas/widgets/struct.Grid.html).
661///
662/// [`kas::CellCollection`]: https://docs.rs/kas/latest/kas/trait.CellCollection.html
663/// [`align`]: https://docs.rs/kas/latest/kas/widgets/adapt/trait.AdaptWidget.html#method.align
664/// [`pack`]: https://docs.rs/kas/latest/kas/widgets/adapt/trait.AdaptWidget.html#method.pack
665/// [`with_stretch`]: https://docs.rs/kas/latest/kas/widgets/adapt/trait.AdaptWidget.html#method.with_stretch
666/// [`with_margin_style`]: https://docs.rs/kas/latest/kas/widgets/adapt/trait.AdaptWidget.html#method.with_margin_style
667#[proc_macro_error]
668#[proc_macro]
669pub fn cell_collection(input: TokenStream) -> TokenStream {
670 parse_macro_input!(input as collection::CellCollection)
671 .expand()
672 .into()
673}
674
675/// A limited form of class inheritance
676///
677/// For supported traits (see below), this macro implements missing trait
678/// methods as a wrapper over the same method on a specified *base*.
679///
680/// ## Supported usage
681///
682/// ### ThemeDraw
683///
684/// Attribute parameters:
685///
686/// > `ThemeDraw` `using` _Expr_
687///
688/// This implements missing `kas::theme::ThemeDraw` methods over the specified
689/// *base* expression _Expr_. This expression is expected to yield an object
690/// implementing `ThemeDraw`. All applicable types should be in scope.
691///
692/// #### Example
693///
694/// ```ignore
695/// #[extends(ThemeDraw using self.base())]
696/// impl ThemeDraw for Object {
697/// // ...
698/// }
699/// ```
700///
701/// Since this example does not provide an implementation of `fn image`, this
702/// macro would provide the implementation below:
703/// ```ignore
704/// fn image(&mut self, id: ImageId, rect: Rect) {
705/// (self.base()).image(id, rect);
706/// }
707/// ```
708/// Each `ThemeDraw` method not implemented in the `impl` block is implemented
709/// by the macro in this manner.
710#[proc_macro_attribute]
711#[proc_macro_error]
712pub fn extends(attr: TokenStream, item: TokenStream) -> TokenStream {
713 match syn::parse::<extends::Extends>(attr) {
714 Ok(extends) => match extends.extend(item.into()) {
715 Ok(result) => result.into(),
716 Err(err) => {
717 emit_call_site_error!(err);
718 TokenStream::new()
719 }
720 },
721 Err(err) => {
722 emit_call_site_error!(err);
723 item
724 }
725 }
726}