diff --git a/src/core/sense.rs b/src/core/sense.rs index ea225fb..e0dadfa 100644 --- a/src/core/sense.rs +++ b/src/core/sense.rs @@ -113,7 +113,7 @@ impl UiModule for SensorModule { self.active .entry(inst.layer) .or_default() - .insert(inst.id.duplicate(), inst.region); + .insert(inst.id, inst.region); } } @@ -126,17 +126,21 @@ impl UiModule for SensorModule { fn on_remove(&mut self, id: &Id) { self.map.remove(id); } + + fn on_move(&mut self, inst: &WidgetInstance) { + if let Some(map) = self.active.get_mut(&inst.layer) + && let Some(region) = map.get_mut(&inst.id) + { + *region = inst.region; + } + } } impl SensorModule { pub fn merge(&mut self, other: Self) { for (id, group) in other.map { for sensor in group.sensors { - self.map - .entry(id.duplicate()) - .or_default() - .sensors - .push(sensor); + self.map.entry(id).or_default().sensors.push(sensor); } } } diff --git a/src/layout/event.rs b/src/layout/event.rs index 693da36..c45bdb6 100644 --- a/src/layout/event.rs +++ b/src/layout/event.rs @@ -57,7 +57,7 @@ impl, Tag> Eventable for W { let id = self.add(ui); ui.modules .get_mut::>() - .register(id.id.duplicate(), event, f); + .register(id.id, event, f); id } } diff --git a/src/layout/id.rs b/src/layout/id.rs index 99a78af..45fdcd5 100644 --- a/src/layout/id.rs +++ b/src/layout/id.rs @@ -10,7 +10,7 @@ use std::{ use crate::{ layout::{FnTag, Ui, Widget, WidgetLike, WidgetTag}, - util::{CopyId, Id, RefCounter}, + util::{Id, RefCounter}, }; pub struct AnyWidget; @@ -44,7 +44,7 @@ pub struct WidgetId { #[repr(C)] pub struct StaticWidgetId { pub(super) ty: TypeId, - pub(super) id: CopyId, + pub(super) id: Id, _pd: PhantomData, } @@ -57,7 +57,7 @@ impl std::fmt::Debug for WidgetId { impl Clone for WidgetId { fn clone(&self) -> Self { Self { - id: self.id.duplicate(), + id: self.id, ty: self.ty, counter: self.counter.clone(), send: self.send.clone(), @@ -89,7 +89,7 @@ impl WidgetId { } pub fn key(&self) -> Id { - self.id.duplicate() + self.id } pub(super) fn cast_type(self) -> WidgetId { @@ -105,7 +105,7 @@ impl WidgetId { self.is_static.store(true, Ordering::Release); StaticWidgetId { ty: self.ty, - id: self.id.copyable(), + id: self.id, _pd: PhantomData, } } @@ -116,7 +116,7 @@ impl WidgetId { let send = self.send.clone(); drop(std::mem::replace( self, - Self::new(other.id.id(), self.ty, send, true), + Self::new(other.id, self.ty, send, true), )); } } @@ -124,7 +124,7 @@ impl WidgetId { impl Drop for WidgetId { fn drop(&mut self) { if self.counter.drop() && !self.is_static.load(Ordering::Acquire) { - let _ = self.send.send(self.id.duplicate()); + let _ = self.send.send(self.id); } } } @@ -194,7 +194,7 @@ impl WidgetId> WidgetLike for F { impl StaticWidgetId { pub fn to_id(&self, send: &Sender) -> WidgetId { - WidgetId::new(self.id.id(), self.ty, send.clone(), true) + WidgetId::new(self.id, self.ty, send.clone(), true) } pub fn any(self) -> StaticWidgetId { // SAFETY: self is repr(C) diff --git a/src/layout/module.rs b/src/layout/module.rs index 5e4feef..4ea672c 100644 --- a/src/layout/module.rs +++ b/src/layout/module.rs @@ -10,6 +10,7 @@ pub trait UiModule: Any { fn on_draw(&mut self, inst: &WidgetInstance) {} fn on_undraw(&mut self, inst: &WidgetInstance) {} fn on_remove(&mut self, id: &Id) {} + fn on_move(&mut self, inst: &WidgetInstance) {} } #[derive(Default)] diff --git a/src/layout/painter.rs b/src/layout/painter.rs index 5e0e657..436f0b4 100644 --- a/src/layout/painter.rs +++ b/src/layout/painter.rs @@ -4,7 +4,7 @@ use crate::{ Textures, UiRegion, UiVec2, Vec2, WidgetId, Widgets, }, render::{Primitive, PrimitiveHandle}, - util::{HashMap, HashSet, Id, IdUtil}, + util::{HashMap, HashSet, Id}, }; pub struct Painter<'a, 'c> { @@ -62,13 +62,13 @@ impl<'a> PainterCtx<'a> { } } - pub fn redraw(&mut self, id: &Id) { + pub fn redraw(&mut self, id: Id) { self.drawing.clear(); - let Some(active) = self.active.get(id) else { + let Some(active) = self.active.get(&id) else { return; }; - if let Some((rid, size)) = &active.resize { + if let Some((rid, size)) = active.resize { let checked = &mut HashMap::default(); let mut ctx = SizeCtx { checked, @@ -77,9 +77,9 @@ impl<'a> PainterCtx<'a> { widgets: self.widgets, }; let desired = ctx.size_inner(id); - if *size != desired { - self.redraw(&rid.duplicate()); - if self.drawing.contains(id) { + if size != desired { + self.redraw(rid); + if self.drawing.contains(&id) { return; } } @@ -93,13 +93,13 @@ impl<'a> PainterCtx<'a> { active.layer, id, active.region, - active.parent.duplicate(), + active.parent, Some(active.children), ); - self.active.get_mut(id).unwrap().resize = active.resize; + self.active.get_mut(&id).unwrap().resize = active.resize; } - pub fn draw(&mut self, id: &Id) { + pub fn draw(&mut self, id: Id) { self.drawing.clear(); self.layers.clear(); self.draw_inner(0, id, UiRegion::full(), None, None); @@ -108,7 +108,7 @@ impl<'a> PainterCtx<'a> { fn draw_inner( &mut self, layer: usize, - id: &Id, + id: Id, region: UiRegion, parent: Option, old_children: Option>, @@ -119,31 +119,32 @@ impl<'a> PainterCtx<'a> { // but this has a very weird issue where you can't move widgets unless u remove first // so swapping is impossible rn I think? // there's definitely better solutions like a counter (>1 = panic) but don't care rn - if self.drawing.contains(id) { + if self.drawing.contains(&id) { panic!("Cannot draw the same widget twice (1)"); } let mut old_children = old_children.unwrap_or_default(); let mut resize = None; - if let Some(active) = self.active.get_mut(id) { + if let Some(active) = self.active.get_mut(&id) { if active.parent != parent { panic!("Cannot draw the same widget twice (2)"); } if active.region == region { return; + } else if active.region.size() == region.size() { + self.mov(id, region); + return; } - // TODO: - // else if active.region.size() == region.size() { move } let active = self.remove(id).unwrap(); old_children = active.children; resize = active.resize; } - self.drawing.insert(id.duplicate()); + self.drawing.insert(id); let mut painter = Painter { region, layer, - id: id.duplicate(), + id, textures: Vec::new(), primitives: Vec::new(), ctx: self, @@ -158,7 +159,7 @@ impl<'a> PainterCtx<'a> { // add to active let instance = WidgetInstance { - id: id.duplicate(), + id, region, parent, textures: painter.textures, @@ -169,24 +170,43 @@ impl<'a> PainterCtx<'a> { }; for (cid, size) in sized_children { if let Some(w) = self.active.get_mut(&cid) { - w.resize = Some((id.duplicate(), size)) + w.resize = Some((id, size)) } } for c in &old_children { if !instance.children.contains(c) { - self.remove_rec(c); + self.remove_rec(*c); } } for m in self.modules.iter_mut() { m.on_draw(&instance); } - self.active.insert(id.duplicate(), instance); + self.active.insert(id, instance); + } + + fn mov(&mut self, id: Id, to: UiRegion) { + let active = self.active.get_mut(&id).unwrap(); + // children will not be changed, so this technically should not be needed + // probably need unsafe + let from = active.region; + for h in &active.primitives { + let region = self.layers[h.layer].primitives.region_mut(h); + *region = region.outside(&from).within(&to); + } + active.region = to; + for m in self.modules.iter_mut() { + m.on_move(active); + } + let children = active.children.clone(); + for child in children { + self.mov(child, to); + } } /// NOTE: instance textures are cleared and self.textures freed - fn remove(&mut self, id: &Id) -> Option { - let mut inst = self.active.remove(id); + fn remove(&mut self, id: Id) -> Option { + let mut inst = self.active.remove(&id); if let Some(inst) = &mut inst { for h in &inst.primitives { self.layers.free(h); @@ -200,11 +220,11 @@ impl<'a> PainterCtx<'a> { inst } - fn remove_rec(&mut self, id: &Id) -> Option { + fn remove_rec(&mut self, id: Id) -> Option { let inst = self.remove(id); if let Some(inst) = &inst { for c in &inst.children { - self.remove_rec(c); + self.remove_rec(*c); } } inst @@ -216,7 +236,7 @@ impl<'a, 'c> Painter<'a, 'c> { let h = self .ctx .layers - .write(self.layer, self.id.duplicate(), primitive, region); + .write(self.layer, self.id, primitive, region); self.primitives.push(h); } @@ -241,9 +261,9 @@ impl<'a, 'c> Painter<'a, 'c> { } fn widget_at(&mut self, id: &WidgetId, region: UiRegion) { - self.children.push(id.id.duplicate()); + self.children.push(id.id); self.ctx - .draw_inner(self.layer, &id.id, region, Some(self.id.duplicate()), None); + .draw_inner(self.layer, id.id, region, Some(self.id), None); } pub fn texture_within(&mut self, handle: &TextureHandle, region: UiRegion) { @@ -308,9 +328,9 @@ pub struct SizeCtx<'a> { } impl SizeCtx<'_> { - fn size_inner(&mut self, id: &Id) -> UiVec2 { + fn size_inner(&mut self, id: Id) -> UiVec2 { let size = self.widgets.get_dyn_dynamic(id).desired_size(self); - self.checked.insert(id.duplicate(), size); + self.checked.insert(id, size); size } pub fn size(&mut self, id: &WidgetId) -> UiVec2 { @@ -318,7 +338,7 @@ impl SizeCtx<'_> { // if let Some(size) = self.checked.get(&id.id) { // return Some(*size); // } - self.size_inner(&id.id) + self.size_inner(id.id) } pub fn draw_text( &mut self, diff --git a/src/layout/pos.rs b/src/layout/pos.rs index bb15aa3..6ac2c61 100644 --- a/src/layout/pos.rs +++ b/src/layout/pos.rs @@ -1,6 +1,6 @@ use crate::{ layout::{Align, Axis, Vec2}, - util::{F32Util, impl_op}, + util::{LerpUtil, impl_op}, }; #[repr(C)] @@ -52,23 +52,26 @@ impl UiVec2 { } pub const fn within(&self, region: &UiRegion) -> UiVec2 { - let anchor = self.rel.lerp(region.top_left.rel, region.bot_right.rel); - let offset = self.abs + self.rel.lerp(region.top_left.abs, region.bot_right.abs); - UiVec2 { - rel: anchor, - abs: offset, - } + let rel = self.rel.lerp(region.top_left.rel, region.bot_right.rel); + let abs = self.abs + self.rel.lerp(region.top_left.abs, region.bot_right.abs); + UiVec2 { rel, abs } + } + + pub const fn outside(&self, region: &UiRegion) -> UiVec2 { + let rel = self.rel.lerp_inv(region.top_left.rel, region.bot_right.rel); + let abs = self.abs - rel.lerp(region.top_left.abs, region.bot_right.abs); + UiVec2 { rel, abs } } pub fn axis_mut(&mut self, axis: Axis) -> UiScalarView<'_> { match axis { Axis::X => UiScalarView { - anchor: &mut self.rel.x, - offset: &mut self.abs.x, + rel: &mut self.rel.x, + abs: &mut self.abs.x, }, Axis::Y => UiScalarView { - anchor: &mut self.rel.y, - offset: &mut self.abs.y, + rel: &mut self.rel.y, + abs: &mut self.abs.y, }, } } @@ -110,6 +113,9 @@ impl UiVec2 { } } +impl_op!(UiVec2 Add add; rel abs); +impl_op!(UiVec2 Sub sub; rel abs); + impl const From for UiVec2 { fn from(align: Align) -> Self { Self::anchor(align.anchor()) @@ -204,6 +210,12 @@ impl UiRegion { bot_right: self.bot_right.within(parent), } } + pub fn outside(&self, parent: &Self) -> Self { + Self { + top_left: self.top_left.outside(parent), + bot_right: self.bot_right.outside(parent), + } + } pub fn axis_mut(&mut self, axis: Axis) -> UIRegionAxisView<'_> { UIRegionAxisView { top_left: self.top_left.axis_mut(axis), @@ -243,6 +255,10 @@ impl UiRegion { self.bot_right.to_size(size) - self.top_left.to_size(size) } + pub fn size(&self) -> UiVec2 { + self.bot_right - self.top_left + } + pub fn select_aligned(&self, size: Vec2, align: Align) -> Self { Self::from_size_align(size, align).within(self) } @@ -292,19 +308,19 @@ pub struct UIRegionAxisView<'a> { } pub struct UiScalarView<'a> { - pub anchor: &'a mut f32, - pub offset: &'a mut f32, + pub rel: &'a mut f32, + pub abs: &'a mut f32, } impl UiScalarView<'_> { pub fn set(&mut self, scalar: UiScalar) { - *self.anchor = scalar.rel; - *self.offset = scalar.abs; + *self.rel = scalar.rel; + *self.abs = scalar.abs; } pub fn get(self) -> UiScalar { UiScalar { - rel: *self.anchor, - abs: *self.offset, + rel: *self.rel, + abs: *self.abs, } } } diff --git a/src/layout/ui.rs b/src/layout/ui.rs index e3e2c43..0563ace 100644 --- a/src/layout/ui.rs +++ b/src/layout/ui.rs @@ -59,12 +59,12 @@ impl Ui { pub fn push(&mut self, w: W) -> WidgetId { let id = self.id(); - self.widgets.insert(id.id.duplicate(), w); + self.widgets.insert(id.id, w); id } pub fn set(&mut self, id: &WidgetId, w: W) { - self.widgets.insert(id.id.duplicate(), w); + self.widgets.insert(id.id, w); } pub fn set_root(&mut self, w: impl WidgetLike) { @@ -120,7 +120,7 @@ impl Ui { self.size, ); if let Some(root) = &self.root { - ctx.draw(&root.id); + ctx.draw(root.id); } } @@ -144,7 +144,7 @@ impl Ui { self.size, ); for id in self.updates.drain(..) { - ctx.redraw(&id); + ctx.redraw(id); } self.free(); } @@ -173,7 +173,7 @@ impl Ui { } pub fn text(&mut self, id: &WidgetId) -> TextEditCtx<'_> { - self.updates.push(id.id.duplicate()); + self.updates.push(id.id); TextEditCtx { text: self.widgets.get_mut(id).unwrap(), font_system: &mut self.text.font_system, @@ -191,7 +191,7 @@ impl Index<&WidgetId> for Ui { impl IndexMut<&WidgetId> for Ui { fn index_mut(&mut self, id: &WidgetId) -> &mut Self::Output { - self.updates.push(id.id.duplicate()); + self.updates.push(id.id); self.get_mut(id).unwrap() } } @@ -206,7 +206,7 @@ impl Index> for Ui { impl IndexMut> for Ui { fn index_mut(&mut self, id: StaticWidgetId) -> &mut Self::Output { - self.updates.push(id.id.id()); + self.updates.push(id.id); self.widgets.get_static_mut(&id).unwrap() } } diff --git a/src/layout/vec2.rs b/src/layout/vec2.rs index 201fc8e..8cc6995 100644 --- a/src/layout/vec2.rs +++ b/src/layout/vec2.rs @@ -1,6 +1,6 @@ use crate::{ layout::UiNum, - util::{F32Util, impl_op}, + util::{DivOr, impl_op}, }; use std::ops::*; @@ -23,15 +23,6 @@ impl Vec2 { Self { x, y } } - pub const fn lerp(self, from: impl const Into, to: impl const Into) -> Self { - let from = from.into(); - let to = to.into(); - Self { - x: self.x.lerp(from.x, to.x), - y: self.y.lerp(from.y, to.y), - } - } - pub const fn round(self) -> Self { Self { x: self.x.round(), @@ -69,6 +60,15 @@ impl_op!(Vec2 Sub sub; x y); impl_op!(Vec2 Mul mul; x y); impl_op!(Vec2 Div div; x y); +impl const DivOr for Vec2 { + fn div_or(self, rhs: Self, other: Self) -> Self { + Self { + x: self.x.div_or(rhs.x, other.x), + y: self.y.div_or(rhs.y, other.y), + } + } +} + impl Neg for Vec2 { type Output = Self; diff --git a/src/layout/widgets.rs b/src/layout/widgets.rs index 262cd28..930b0cc 100644 --- a/src/layout/widgets.rs +++ b/src/layout/widgets.rs @@ -24,22 +24,22 @@ impl Widgets { } } - pub fn get_dyn(&self, id: &Id) -> Option<&dyn Widget> { - Some(self.map.get(id)?.widget.as_ref()) + pub fn get_dyn(&self, id: Id) -> Option<&dyn Widget> { + Some(self.map.get(&id)?.widget.as_ref()) } - pub fn get_dyn_mut(&mut self, id: &Id) -> Option<&mut dyn Widget> { - Some(self.map.get_mut(id)?.widget.as_mut()) + pub fn get_dyn_mut(&mut self, id: Id) -> Option<&mut dyn Widget> { + Some(self.map.get_mut(&id)?.widget.as_mut()) } /// get_dyn but dynamic borrow checking of widgets /// lets you do recursive (tree) operations, like the painter does - pub fn get_dyn_dynamic(&self, id: &Id) -> WidgetWrapper<'_> { + pub fn get_dyn_dynamic(&self, id: Id) -> WidgetWrapper<'_> { // SAFETY: must guarantee no other mutable references to this widget exist // done through the borrow variable #[allow(mutable_transmutes)] let data = unsafe { - std::mem::transmute::<&WidgetData, &mut WidgetData>(self.map.get(id).unwrap()) + std::mem::transmute::<&WidgetData, &mut WidgetData>(self.map.get(&id).unwrap()) }; if data.borrowed { panic!("tried to mutably borrow the same widget twice"); @@ -48,19 +48,19 @@ impl Widgets { } pub fn get_static(&self, id: &StaticWidgetId) -> Option<&W> { - self.get_dyn(&id.id.id())?.as_any().downcast_ref() + self.get_dyn(id.id)?.as_any().downcast_ref() } pub fn get_static_mut(&mut self, id: &StaticWidgetId) -> Option<&mut W> { - self.get_dyn_mut(&id.id.id())?.as_any_mut().downcast_mut() + self.get_dyn_mut(id.id)?.as_any_mut().downcast_mut() } pub fn get(&self, id: &WidgetId) -> Option<&W> { - self.get_dyn(&id.id)?.as_any().downcast_ref() + self.get_dyn(id.id)?.as_any().downcast_ref() } pub fn get_mut(&mut self, id: &WidgetId) -> Option<&mut W> { - self.get_dyn_mut(&id.id)?.as_any_mut().downcast_mut() + self.get_dyn_mut(id.id)?.as_any_mut().downcast_mut() } pub fn insert(&mut self, id: Id, widget: W) { diff --git a/src/lib.rs b/src/lib.rs index ef028d2..4623200 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ #![feature(trait_alias)] #![feature(unboxed_closures)] #![feature(fn_traits)] +#![feature(const_cmp)] pub mod core; pub mod layout; diff --git a/src/render/primitive.rs b/src/render/primitive.rs index 0cbfc48..5fa9b41 100644 --- a/src/render/primitive.rs +++ b/src/render/primitive.rs @@ -132,7 +132,7 @@ impl Primitives { if i == self.instances.len() { return None; } - let id = self.assoc[i].duplicate(); + let id = self.assoc[i]; let old = self.instances.len(); Some(PrimitiveChange { id, old, new: i }) }) @@ -150,6 +150,11 @@ impl Primitives { pub fn instances(&self) -> &Vec { &self.instances } + + pub fn region_mut(&mut self, h: &PrimitiveHandle) -> &mut UiRegion { + self.updated = true; + &mut self.instances[h.inst_idx].region + } } pub struct PrimitiveChange { diff --git a/src/util/id.rs b/src/util/id.rs index 79632e2..f3d73b1 100644 --- a/src/util/id.rs +++ b/src/util/id.rs @@ -1,9 +1,4 @@ -/// intentionally does not implement copy or clone -/// which should make it harder to misuse; -/// the idea is to generally try to guarantee all IDs -/// point to something valid, although duplicate -/// gets around this if needed -#[derive(Eq, Hash, PartialEq, Debug)] +#[derive(Eq, Hash, PartialEq, Debug, Clone, Copy)] pub struct Id(u64); #[derive(Default)] @@ -28,39 +23,3 @@ impl IdTracker { self.free.push(id); } } - -impl Id { - /// this must be used carefully to make sure - /// all IDs are still valid references; - /// named weirdly to indicate this. - /// generally should not be used in "user" code - pub fn duplicate(&self) -> Self { - Self(self.0) - } - - /// this must be used carefully to make sure - /// all IDs are still valid references. - /// generally should not be used in "user" code - pub fn copyable(&self) -> CopyId { - CopyId(self.0) - } -} - -#[derive(Eq, Hash, PartialEq, Debug, Clone, Copy)] -pub struct CopyId(u64); - -impl CopyId { - pub fn id(&self) -> Id { - Id(self.0) - } -} - -pub trait IdUtil { - fn duplicate(&self) -> Self; -} - -impl IdUtil for Option { - fn duplicate(&self) -> Self { - self.as_ref().map(|i| i.duplicate()) - } -} diff --git a/src/util/math.rs b/src/util/math.rs index 5a7a28a..744889b 100644 --- a/src/util/math.rs +++ b/src/util/math.rs @@ -1,60 +1,82 @@ use std::ops::*; #[const_trait] -pub trait F32Util { - fn lerp + const Add>(self, from: T, to: T) -> T; +pub trait LerpUtil { + fn lerp(self, from: Self, to: Self) -> Self; + fn lerp_inv(self, from: Self, to: Self) -> Self; } -impl const F32Util for f32 { - fn lerp + const Add>(self, from: T, to: T) -> T { - from * (1.0 - self) + to * self +#[const_trait] +pub trait DivOr { + fn div_or(self, rhs: Self, other: Self) -> Self; +} + +impl const DivOr for f32 { + fn div_or(self, rhs: Self, other: Self) -> Self { + let res = self / rhs; + if res.is_nan() { other } else { res } + } +} + +impl + const Sub + const Mul + const DivOr + Copy> const + LerpUtil for T +{ + /// linear interpolation + /// from * (1.0 - self) + to * self + fn lerp(self, from: Self, to: Self) -> Self { + from + (to - from) * self + } + /// inverse of lerp + fn lerp_inv(self, from: Self, to: Self) -> Self { + (self - from).div_or(to - from, from) } } macro_rules! impl_op { ($T:ident $op:ident $fn:ident $opa:ident $fna:ident; $($field:ident)*) => { - mod ${concat(op_, $fn, _impl)} { - use super::*; - #[allow(unused_imports)] - use std::ops::*; - impl const $op for $T { - type Output = Self; + #[allow(non_snake_case)] + mod ${concat($T, _op_, $fn, _impl)} { + use super::*; + #[allow(unused_imports)] + use std::ops::*; + impl const $op for $T { + type Output = Self; - fn $fn(self, rhs: Self) -> Self::Output { - Self { - $($field: self.$field.$fn(rhs.$field),)* + fn $fn(self, rhs: Self) -> Self::Output { + Self { + $($field: self.$field.$fn(rhs.$field),)* + } + } + } + impl const $opa for $T { + fn $fna(&mut self, rhs: Self) { + $(self.$field.$fna(rhs.$field);)* + } + } + impl const $op for $T { + type Output = Self; + + fn $fn(self, rhs: f32) -> Self::Output { + Self { + $($field: self.$field.$fn(rhs),)* + } + } + } + impl const $op<$T> for f32 { + type Output = $T; + + fn $fn(self, rhs: $T) -> Self::Output { + $T { + $($field: self.$fn(rhs.$field),)* + } + } + } + impl const $opa for $T { + fn $fna(&mut self, rhs: f32) { + $(self.$field.$fna(rhs);)* } } } - impl const $opa for $T { - fn $fna(&mut self, rhs: Self) { - $(self.$field.$fna(rhs.$field);)* - } - } - impl const $op for $T { - type Output = Self; - - fn $fn(self, rhs: f32) -> Self::Output { - Self { - $($field: self.$field.$fn(rhs),)* - } - } - } - impl const $op<$T> for f32 { - type Output = $T; - - fn $fn(self, rhs: $T) -> Self::Output { - $T { - $($field: self.$fn(rhs.$field),)* - } - } - } - impl const $opa for $T { - fn $fna(&mut self, rhs: f32) { - $(self.$field.$fna(rhs);)* - } - } - } }; ($T:ident $op:ident $fn:ident; $($field:ident)*) => { impl_op!($T $op $fn ${concat($op,Assign)} ${concat($fn,_assign)}; $($field)*);