Make GridPlacement's fields non-zero and add accessor functions. (#9486)
				
					
				
			# Objective * There is no way to read the fields of `GridPlacement` once set. * Values of `0` for `GridPlacement`'s fields are invalid but can be set. * A non-zero representation would be half the size. fixes #9474 ## Solution * Add `get_start`, `get_end` and `get_span` accessor methods. * Change`GridPlacement`'s constructor functions to panic on arguments of zero. * Use non-zero types instead of primitives for `GridPlacement`'s fields. --- ## Changelog `bevy_ui::ui_node::GridPlacement`: * Field types have been changed to `Option<NonZeroI16>` and `Option<NonZeroU16>`. This is because zero values are not valid for `GridPlacement`. Previously, Taffy interpreted these as auto variants. * Constructor functions for `GridPlacement` panic on arguments of `0`. * Added accessor functions: `get_start`, `get_end`, and `get_span`. These return the inner primitive value (if present) of the respective fields. ## Migration Guide `GridPlacement`'s constructor functions no longer accept values of `0`. Given any argument of `0` they will panic with a `GridPlacementError`.
This commit is contained in:
		
							parent
							
								
									394e2b0c91
								
							
						
					
					
						commit
						a2bd93aedc
					
				| @ -278,8 +278,8 @@ impl From<GridAutoFlow> for taffy::style::GridAutoFlow { | |||||||
| 
 | 
 | ||||||
| impl From<GridPlacement> for taffy::geometry::Line<taffy::style::GridPlacement> { | impl From<GridPlacement> for taffy::geometry::Line<taffy::style::GridPlacement> { | ||||||
|     fn from(value: GridPlacement) -> Self { |     fn from(value: GridPlacement) -> Self { | ||||||
|         let span = value.span.unwrap_or(1).max(1); |         let span = value.get_span().unwrap_or(1); | ||||||
|         match (value.start, value.end) { |         match (value.get_start(), value.get_end()) { | ||||||
|             (Some(start), Some(end)) => taffy::geometry::Line { |             (Some(start), Some(end)) => taffy::geometry::Line { | ||||||
|                 start: style_helpers::line(start), |                 start: style_helpers::line(start), | ||||||
|                 end: style_helpers::line(end), |                 end: style_helpers::line(end), | ||||||
|  | |||||||
| @ -10,7 +10,10 @@ use bevy_render::{ | |||||||
| use bevy_transform::prelude::GlobalTransform; | use bevy_transform::prelude::GlobalTransform; | ||||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||||
| use smallvec::SmallVec; | use smallvec::SmallVec; | ||||||
| use std::ops::{Div, DivAssign, Mul, MulAssign}; | use std::{ | ||||||
|  |     num::{NonZeroI16, NonZeroU16}, | ||||||
|  |     ops::{Div, DivAssign, Mul, MulAssign}, | ||||||
|  | }; | ||||||
| use thiserror::Error; | use thiserror::Error; | ||||||
| 
 | 
 | ||||||
| /// Describes the size of a UI node
 | /// Describes the size of a UI node
 | ||||||
| @ -1470,100 +1473,145 @@ impl From<RepeatedGridTrack> for Vec<RepeatedGridTrack> { | |||||||
| /// <https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Line-based_Placement_with_CSS_Grid>
 | /// <https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Line-based_Placement_with_CSS_Grid>
 | ||||||
| pub struct GridPlacement { | pub struct GridPlacement { | ||||||
|     /// The grid line at which the item should start. Lines are 1-indexed. Negative indexes count backwards from the end of the grid. Zero is not a valid index.
 |     /// The grid line at which the item should start. Lines are 1-indexed. Negative indexes count backwards from the end of the grid. Zero is not a valid index.
 | ||||||
|     pub(crate) start: Option<i16>, |     pub(crate) start: Option<NonZeroI16>, | ||||||
|     /// How many grid tracks the item should span. Defaults to 1.
 |     /// How many grid tracks the item should span. Defaults to 1.
 | ||||||
|     pub(crate) span: Option<u16>, |     pub(crate) span: Option<NonZeroU16>, | ||||||
|     /// The grid line at which the node should end. Lines are 1-indexed. Negative indexes count backwards from the end of the grid. Zero is not a valid index.
 |     /// The grid line at which the item should end. Lines are 1-indexed. Negative indexes count backwards from the end of the grid. Zero is not a valid index.
 | ||||||
|     pub(crate) end: Option<i16>, |     pub(crate) end: Option<NonZeroI16>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl GridPlacement { | impl GridPlacement { | ||||||
|     pub const DEFAULT: Self = Self { |     pub const DEFAULT: Self = Self { | ||||||
|         start: None, |         start: None, | ||||||
|         span: Some(1), |         span: Some(unsafe { NonZeroU16::new_unchecked(1) }), | ||||||
|         end: None, |         end: None, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     /// Place the grid item automatically (letting the `span` default to `1`).
 |     /// Place the grid item automatically (letting the `span` default to `1`).
 | ||||||
|     pub fn auto() -> Self { |     pub fn auto() -> Self { | ||||||
|         Self { |         Self::DEFAULT | ||||||
|             start: None, |  | ||||||
|             end: None, |  | ||||||
|             span: Some(1), |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Place the grid item automatically, specifying how many tracks it should `span`.
 |     /// Place the grid item automatically, specifying how many tracks it should `span`.
 | ||||||
|  |     ///
 | ||||||
|  |     /// # Panics
 | ||||||
|  |     ///
 | ||||||
|  |     /// Panics if `span` is `0`
 | ||||||
|     pub fn span(span: u16) -> Self { |     pub fn span(span: u16) -> Self { | ||||||
|         Self { |         Self { | ||||||
|             start: None, |             start: None, | ||||||
|             end: None, |             end: None, | ||||||
|             span: Some(span), |             span: try_into_grid_span(span).expect("Invalid span value of 0."), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Place the grid item specifying the `start` grid line (letting the `span` default to `1`).
 |     /// Place the grid item specifying the `start` grid line (letting the `span` default to `1`).
 | ||||||
|  |     ///
 | ||||||
|  |     /// # Panics
 | ||||||
|  |     ///
 | ||||||
|  |     /// Panics if `start` is `0`
 | ||||||
|     pub fn start(start: i16) -> Self { |     pub fn start(start: i16) -> Self { | ||||||
|         Self { |         Self { | ||||||
|             start: Some(start), |             start: try_into_grid_index(start).expect("Invalid start value of 0."), | ||||||
|             end: None, |             ..Self::DEFAULT | ||||||
|             span: Some(1), |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Place the grid item specifying the `end` grid line (letting the `span` default to `1`).
 |     /// Place the grid item specifying the `end` grid line (letting the `span` default to `1`).
 | ||||||
|  |     ///
 | ||||||
|  |     /// # Panics
 | ||||||
|  |     ///
 | ||||||
|  |     /// Panics if `end` is `0`
 | ||||||
|     pub fn end(end: i16) -> Self { |     pub fn end(end: i16) -> Self { | ||||||
|         Self { |         Self { | ||||||
|             start: None, |             end: try_into_grid_index(end).expect("Invalid end value of 0."), | ||||||
|             end: Some(end), |             ..Self::DEFAULT | ||||||
|             span: Some(1), |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Place the grid item specifying the `start` grid line and how many tracks it should `span`.
 |     /// Place the grid item specifying the `start` grid line and how many tracks it should `span`.
 | ||||||
|  |     ///
 | ||||||
|  |     /// # Panics
 | ||||||
|  |     ///
 | ||||||
|  |     /// Panics if `start` or `span` is `0`
 | ||||||
|     pub fn start_span(start: i16, span: u16) -> Self { |     pub fn start_span(start: i16, span: u16) -> Self { | ||||||
|         Self { |         Self { | ||||||
|             start: Some(start), |             start: try_into_grid_index(start).expect("Invalid start value of 0."), | ||||||
|             end: None, |             end: None, | ||||||
|             span: Some(span), |             span: try_into_grid_span(span).expect("Invalid span value of 0."), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Place the grid item specifying `start` and `end` grid lines (`span` will be inferred)
 |     /// Place the grid item specifying `start` and `end` grid lines (`span` will be inferred)
 | ||||||
|  |     ///
 | ||||||
|  |     /// # Panics
 | ||||||
|  |     ///
 | ||||||
|  |     /// Panics if `start` or `end` is `0`
 | ||||||
|     pub fn start_end(start: i16, end: i16) -> Self { |     pub fn start_end(start: i16, end: i16) -> Self { | ||||||
|         Self { |         Self { | ||||||
|             start: Some(start), |             start: try_into_grid_index(start).expect("Invalid start value of 0."), | ||||||
|             end: Some(end), |             end: try_into_grid_index(end).expect("Invalid end value of 0."), | ||||||
|             span: None, |             span: None, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Place the grid item specifying the `end` grid line and how many tracks it should `span`.
 |     /// Place the grid item specifying the `end` grid line and how many tracks it should `span`.
 | ||||||
|  |     ///
 | ||||||
|  |     /// # Panics
 | ||||||
|  |     ///
 | ||||||
|  |     /// Panics if `end` or `span` is `0`
 | ||||||
|     pub fn end_span(end: i16, span: u16) -> Self { |     pub fn end_span(end: i16, span: u16) -> Self { | ||||||
|         Self { |         Self { | ||||||
|             start: None, |             start: None, | ||||||
|             end: Some(end), |             end: try_into_grid_index(end).expect("Invalid end value of 0."), | ||||||
|             span: Some(span), |             span: try_into_grid_span(span).expect("Invalid span value of 0."), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Mutate the item, setting the `start` grid line
 |     /// Mutate the item, setting the `start` grid line
 | ||||||
|  |     ///
 | ||||||
|  |     /// # Panics
 | ||||||
|  |     ///
 | ||||||
|  |     /// Panics if `start` is `0`
 | ||||||
|     pub fn set_start(mut self, start: i16) -> Self { |     pub fn set_start(mut self, start: i16) -> Self { | ||||||
|         self.start = Some(start); |         self.start = try_into_grid_index(start).expect("Invalid start value of 0."); | ||||||
|         self |         self | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Mutate the item, setting the `end` grid line
 |     /// Mutate the item, setting the `end` grid line
 | ||||||
|  |     ///
 | ||||||
|  |     /// # Panics
 | ||||||
|  |     ///
 | ||||||
|  |     /// Panics if `end` is `0`
 | ||||||
|     pub fn set_end(mut self, end: i16) -> Self { |     pub fn set_end(mut self, end: i16) -> Self { | ||||||
|         self.end = Some(end); |         self.end = try_into_grid_index(end).expect("Invalid end value of 0."); | ||||||
|         self |         self | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Mutate the item, setting the number of tracks the item should `span`
 |     /// Mutate the item, setting the number of tracks the item should `span`
 | ||||||
|  |     ///
 | ||||||
|  |     /// # Panics
 | ||||||
|  |     ///
 | ||||||
|  |     /// Panics if `span` is `0`
 | ||||||
|     pub fn set_span(mut self, span: u16) -> Self { |     pub fn set_span(mut self, span: u16) -> Self { | ||||||
|         self.span = Some(span); |         self.span = try_into_grid_span(span).expect("Invalid span value of 0."); | ||||||
|         self |         self | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     /// Returns the grid line at which the item should start, or `None` if not set.
 | ||||||
|  |     pub fn get_start(self) -> Option<i16> { | ||||||
|  |         self.start.map(NonZeroI16::get) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Returns the grid line at which the item should end, or `None` if not set.
 | ||||||
|  |     pub fn get_end(self) -> Option<i16> { | ||||||
|  |         self.end.map(NonZeroI16::get) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Returns span for this grid item, or `None` if not set.
 | ||||||
|  |     pub fn get_span(self) -> Option<u16> { | ||||||
|  |         self.span.map(NonZeroU16::get) | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Default for GridPlacement { | impl Default for GridPlacement { | ||||||
| @ -1572,6 +1620,29 @@ impl Default for GridPlacement { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Convert an `i16` to `NonZeroI16`, fails on `0` and returns the `InvalidZeroIndex` error.
 | ||||||
|  | fn try_into_grid_index(index: i16) -> Result<Option<NonZeroI16>, GridPlacementError> { | ||||||
|  |     Ok(Some( | ||||||
|  |         NonZeroI16::new(index).ok_or(GridPlacementError::InvalidZeroIndex)?, | ||||||
|  |     )) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Convert a `u16` to `NonZeroU16`, fails on `0` and returns the `InvalidZeroSpan` error.
 | ||||||
|  | fn try_into_grid_span(span: u16) -> Result<Option<NonZeroU16>, GridPlacementError> { | ||||||
|  |     Ok(Some( | ||||||
|  |         NonZeroU16::new(span).ok_or(GridPlacementError::InvalidZeroSpan)?, | ||||||
|  |     )) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Errors that occur when setting contraints for a `GridPlacement`
 | ||||||
|  | #[derive(Debug, Eq, PartialEq, Clone, Copy, Error)] | ||||||
|  | pub enum GridPlacementError { | ||||||
|  |     #[error("Zero is not a valid grid position")] | ||||||
|  |     InvalidZeroIndex, | ||||||
|  |     #[error("Spans cannot be zero length")] | ||||||
|  |     InvalidZeroSpan, | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /// The background color of the node
 | /// The background color of the node
 | ||||||
| ///
 | ///
 | ||||||
| /// This serves as the "fill" color.
 | /// This serves as the "fill" color.
 | ||||||
| @ -1719,6 +1790,7 @@ impl Default for ZIndex { | |||||||
| 
 | 
 | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod tests { | mod tests { | ||||||
|  |     use crate::GridPlacement; | ||||||
|     use crate::ValArithmeticError; |     use crate::ValArithmeticError; | ||||||
| 
 | 
 | ||||||
|     use super::Val; |     use super::Val; | ||||||
| @ -1867,4 +1939,30 @@ mod tests { | |||||||
|     fn default_val_equals_const_default_val() { |     fn default_val_equals_const_default_val() { | ||||||
|         assert_eq!(Val::default(), Val::DEFAULT); |         assert_eq!(Val::default(), Val::DEFAULT); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn invalid_grid_placement_values() { | ||||||
|  |         assert!(std::panic::catch_unwind(|| GridPlacement::span(0)).is_err()); | ||||||
|  |         assert!(std::panic::catch_unwind(|| GridPlacement::start(0)).is_err()); | ||||||
|  |         assert!(std::panic::catch_unwind(|| GridPlacement::end(0)).is_err()); | ||||||
|  |         assert!(std::panic::catch_unwind(|| GridPlacement::start_end(0, 1)).is_err()); | ||||||
|  |         assert!(std::panic::catch_unwind(|| GridPlacement::start_end(-1, 0)).is_err()); | ||||||
|  |         assert!(std::panic::catch_unwind(|| GridPlacement::start_span(1, 0)).is_err()); | ||||||
|  |         assert!(std::panic::catch_unwind(|| GridPlacement::start_span(0, 1)).is_err()); | ||||||
|  |         assert!(std::panic::catch_unwind(|| GridPlacement::end_span(0, 1)).is_err()); | ||||||
|  |         assert!(std::panic::catch_unwind(|| GridPlacement::end_span(1, 0)).is_err()); | ||||||
|  |         assert!(std::panic::catch_unwind(|| GridPlacement::default().set_start(0)).is_err()); | ||||||
|  |         assert!(std::panic::catch_unwind(|| GridPlacement::default().set_end(0)).is_err()); | ||||||
|  |         assert!(std::panic::catch_unwind(|| GridPlacement::default().set_span(0)).is_err()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn grid_placement_accessors() { | ||||||
|  |         assert_eq!(GridPlacement::start(5).get_start(), Some(5)); | ||||||
|  |         assert_eq!(GridPlacement::end(-4).get_end(), Some(-4)); | ||||||
|  |         assert_eq!(GridPlacement::span(2).get_span(), Some(2)); | ||||||
|  |         assert_eq!(GridPlacement::start_end(11, 21).get_span(), None); | ||||||
|  |         assert_eq!(GridPlacement::start_span(3, 5).get_end(), None); | ||||||
|  |         assert_eq!(GridPlacement::end_span(-4, 12).get_start(), None); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 ickshonpe
						ickshonpe