layout.rs (30295B)
1 use crate::change::Disposition; 2 use crate::decoration::Decoration; 3 use crate::decoration::Frame; 4 use crate::error::StateChangeError; 5 use crate::identify::Ident; 6 use crate::identify::Identify; 7 use crate::placement::PlacementMethod; 8 use crate::zone::Zone; 9 10 use winsys::geometry::Dim; 11 use winsys::geometry::Extents; 12 use winsys::geometry::Padding; 13 use winsys::geometry::Pos; 14 use winsys::geometry::Region; 15 16 use strum::EnumCount; 17 use strum::IntoEnumIterator; 18 use strum_macros::EnumIter; 19 use strum_macros::ToString; 20 21 use std::collections::HashMap; 22 use std::string::ToString; 23 use std::vec::Vec; 24 25 type LayoutFn = fn(&Region, &LayoutData, Vec<bool>) -> Vec<(Disposition, bool)>; 26 27 #[non_exhaustive] 28 #[derive(Debug, PartialEq, Clone, Copy)] 29 pub struct LayoutConfig { 30 pub method: PlacementMethod, 31 pub decoration: Decoration, 32 pub root_only: bool, 33 pub margin: bool, 34 pub gap: bool, 35 pub persistent: bool, 36 pub single: bool, 37 pub wraps: bool, 38 } 39 40 impl Default for LayoutConfig { 41 fn default() -> Self { 42 Self { 43 method: PlacementMethod::Free, 44 decoration: Default::default(), 45 root_only: true, 46 margin: false, 47 gap: false, 48 persistent: false, 49 single: false, 50 wraps: true, 51 } 52 } 53 } 54 55 #[non_exhaustive] 56 #[derive(Debug, PartialEq, Clone, Copy)] 57 pub struct LayoutData { 58 /// Generic layout data 59 pub margin: Padding, 60 pub gap_size: u32, 61 62 /// Tiled layout data 63 pub main_count: u32, 64 pub main_factor: f32, 65 } 66 67 impl Default for LayoutData { 68 fn default() -> Self { 69 Self { 70 margin: Default::default(), 71 gap_size: 0u32, 72 73 main_count: 1u32, 74 main_factor: 0.50f32, 75 } 76 } 77 } 78 79 #[non_exhaustive] 80 #[repr(u8)] 81 #[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, EnumIter, EnumCount, ToString)] 82 pub enum LayoutKind { 83 /// Free layouts 84 Float = b'f', 85 BLFloat = b'F', 86 SingleFloat = b'z', 87 BLSingleFloat = b'Z', 88 89 /// Tiled layouts 90 // Overlapping 91 Center = b';', 92 Monocle = b'%', 93 // Non-overlapping 94 Paper = b'p', 95 SPaper = b'P', 96 Stack = b's', 97 SStack = b'S', 98 BStack = b'b', 99 SBStack = b'B', 100 Horz = b'h', 101 SHorz = b'H', 102 Vert = b'v', 103 SVert = b'V', 104 } 105 106 impl LayoutKind { 107 pub fn symbol(&self) -> char { 108 (*self as u8) as char 109 } 110 111 pub fn name(&self) -> String { 112 self.to_string() 113 } 114 115 pub fn config(&self) -> LayoutConfig { 116 match *self { 117 LayoutKind::Float => LayoutConfig { 118 method: PlacementMethod::Free, 119 decoration: Decoration::FREE_DECORATION, 120 root_only: true, 121 margin: false, 122 gap: false, 123 persistent: false, 124 single: false, 125 wraps: true, 126 }, 127 LayoutKind::BLFloat => LayoutConfig { 128 method: PlacementMethod::Free, 129 decoration: Decoration::NO_DECORATION, 130 root_only: true, 131 margin: false, 132 gap: false, 133 persistent: false, 134 single: false, 135 wraps: true, 136 }, 137 LayoutKind::SingleFloat => LayoutConfig { 138 method: PlacementMethod::Free, 139 decoration: Decoration::FREE_DECORATION, 140 root_only: true, 141 margin: false, 142 gap: false, 143 persistent: true, 144 single: true, 145 wraps: true, 146 }, 147 LayoutKind::BLSingleFloat => LayoutConfig { 148 method: PlacementMethod::Free, 149 decoration: Decoration::NO_DECORATION, 150 root_only: true, 151 margin: false, 152 gap: false, 153 persistent: true, 154 single: true, 155 wraps: true, 156 }, 157 LayoutKind::Center => LayoutConfig { 158 method: PlacementMethod::Tile, 159 decoration: Decoration::NO_DECORATION, 160 root_only: false, 161 margin: true, 162 gap: true, 163 persistent: false, 164 single: false, 165 wraps: true, 166 }, 167 LayoutKind::Monocle => LayoutConfig { 168 method: PlacementMethod::Tile, 169 decoration: Decoration::NO_DECORATION, 170 root_only: false, 171 margin: true, 172 gap: true, 173 persistent: false, 174 single: false, 175 wraps: true, 176 }, 177 LayoutKind::Paper => LayoutConfig { 178 method: PlacementMethod::Tile, 179 decoration: Decoration { 180 frame: Some(Frame { 181 extents: Extents { 182 left: 1, 183 right: 1, 184 top: 0, 185 bottom: 0, 186 }, 187 colors: Default::default(), 188 }), 189 border: None, 190 }, 191 root_only: false, 192 margin: true, 193 gap: true, 194 persistent: true, 195 single: false, 196 wraps: false, 197 }, 198 LayoutKind::SPaper => LayoutConfig { 199 method: PlacementMethod::Tile, 200 decoration: Decoration { 201 frame: Some(Frame { 202 extents: Extents { 203 left: 1, 204 right: 1, 205 top: 0, 206 bottom: 0, 207 }, 208 colors: Default::default(), 209 }), 210 border: None, 211 }, 212 root_only: false, 213 margin: true, 214 gap: false, 215 persistent: true, 216 single: false, 217 wraps: false, 218 }, 219 LayoutKind::Stack => LayoutConfig { 220 method: PlacementMethod::Tile, 221 decoration: Decoration { 222 frame: Some(Frame { 223 extents: Extents { 224 left: 0, 225 right: 0, 226 top: 3, 227 bottom: 0, 228 }, 229 colors: Default::default(), 230 }), 231 border: None, 232 }, 233 root_only: false, 234 margin: true, 235 gap: true, 236 persistent: false, 237 single: false, 238 wraps: true, 239 }, 240 LayoutKind::SStack => LayoutConfig { 241 method: PlacementMethod::Tile, 242 decoration: Decoration { 243 frame: Some(Frame { 244 extents: Extents { 245 left: 0, 246 right: 0, 247 top: 3, 248 bottom: 0, 249 }, 250 colors: Default::default(), 251 }), 252 border: None, 253 }, 254 root_only: false, 255 margin: true, 256 gap: false, 257 persistent: false, 258 single: false, 259 wraps: true, 260 }, 261 LayoutKind::BStack => LayoutConfig { 262 method: PlacementMethod::Tile, 263 decoration: Decoration { 264 frame: Some(Frame { 265 extents: Extents { 266 left: 0, 267 right: 0, 268 top: 3, 269 bottom: 0, 270 }, 271 colors: Default::default(), 272 }), 273 border: None, 274 }, 275 root_only: false, 276 margin: true, 277 gap: true, 278 persistent: false, 279 single: false, 280 wraps: true, 281 }, 282 LayoutKind::SBStack => LayoutConfig { 283 method: PlacementMethod::Tile, 284 decoration: Decoration { 285 frame: Some(Frame { 286 extents: Extents { 287 left: 0, 288 right: 0, 289 top: 3, 290 bottom: 0, 291 }, 292 colors: Default::default(), 293 }), 294 border: None, 295 }, 296 root_only: false, 297 margin: true, 298 gap: false, 299 persistent: false, 300 single: false, 301 wraps: true, 302 }, 303 LayoutKind::Horz => LayoutConfig { 304 method: PlacementMethod::Tile, 305 decoration: Decoration { 306 frame: Some(Frame { 307 extents: Extents { 308 left: 0, 309 right: 0, 310 top: 3, 311 bottom: 0, 312 }, 313 colors: Default::default(), 314 }), 315 border: None, 316 }, 317 root_only: false, 318 margin: true, 319 gap: true, 320 persistent: false, 321 single: false, 322 wraps: true, 323 }, 324 LayoutKind::SHorz => LayoutConfig { 325 method: PlacementMethod::Tile, 326 decoration: Decoration { 327 frame: Some(Frame { 328 extents: Extents { 329 left: 0, 330 right: 0, 331 top: 3, 332 bottom: 0, 333 }, 334 colors: Default::default(), 335 }), 336 border: None, 337 }, 338 root_only: false, 339 margin: true, 340 gap: false, 341 persistent: false, 342 single: false, 343 wraps: true, 344 }, 345 LayoutKind::Vert => LayoutConfig { 346 method: PlacementMethod::Tile, 347 decoration: Decoration { 348 frame: Some(Frame { 349 extents: Extents { 350 left: 0, 351 right: 0, 352 top: 3, 353 bottom: 0, 354 }, 355 colors: Default::default(), 356 }), 357 border: None, 358 }, 359 root_only: false, 360 margin: true, 361 gap: true, 362 persistent: false, 363 single: false, 364 wraps: true, 365 }, 366 LayoutKind::SVert => LayoutConfig { 367 method: PlacementMethod::Tile, 368 decoration: Decoration { 369 frame: Some(Frame { 370 extents: Extents { 371 left: 0, 372 right: 0, 373 top: 3, 374 bottom: 0, 375 }, 376 colors: Default::default(), 377 }), 378 border: None, 379 }, 380 root_only: false, 381 margin: true, 382 gap: false, 383 persistent: false, 384 single: false, 385 wraps: true, 386 }, 387 388 #[allow(unreachable_patterns)] 389 _ => unimplemented!("{:?} does not have an associated configuration", self), 390 } 391 } 392 393 fn default_data(&self) -> LayoutData { 394 match *self { 395 LayoutKind::Float => Default::default(), 396 LayoutKind::BLFloat => Default::default(), 397 LayoutKind::SingleFloat => Default::default(), 398 LayoutKind::BLSingleFloat => Default::default(), 399 LayoutKind::Center => LayoutData { 400 main_count: 5u32, 401 main_factor: 0.40f32, 402 ..Default::default() 403 }, 404 LayoutKind::Monocle => Default::default(), 405 LayoutKind::Paper => Default::default(), 406 LayoutKind::SPaper => Default::default(), 407 LayoutKind::Stack => LayoutData { 408 main_count: 1u32, 409 main_factor: 0.50f32, 410 ..Default::default() 411 }, 412 LayoutKind::SStack => LayoutData { 413 main_count: 1u32, 414 main_factor: 0.50f32, 415 ..Default::default() 416 }, 417 LayoutKind::BStack => LayoutData { 418 main_count: 1u32, 419 main_factor: 0.50f32, 420 ..Default::default() 421 }, 422 LayoutKind::SBStack => LayoutData { 423 main_count: 1u32, 424 main_factor: 0.50f32, 425 ..Default::default() 426 }, 427 LayoutKind::Horz => Default::default(), 428 LayoutKind::SHorz => Default::default(), 429 LayoutKind::Vert => Default::default(), 430 LayoutKind::SVert => Default::default(), 431 432 #[allow(unreachable_patterns)] 433 _ => unimplemented!("{:?} does not have associated default data", self), 434 } 435 } 436 437 #[inline] 438 fn stack_split( 439 n: usize, 440 n_main: u32, 441 ) -> (i32, i32) { 442 let n_main = n_main as i32; 443 let n = n as i32; 444 445 if n <= n_main { 446 (n, 0i32) 447 } else { 448 (n_main, n - n_main) 449 } 450 } 451 452 fn func(&self) -> LayoutFn { 453 match *self { 454 LayoutKind::Float => |_, _, active_map| { 455 let config = &LayoutKind::Float.config(); 456 vec![(Disposition::Unchanged(config.decoration), true); active_map.len()] 457 }, 458 LayoutKind::BLFloat => |_, _, active_map| { 459 let config = &LayoutKind::BLFloat.config(); 460 vec![(Disposition::Unchanged(config.decoration), true); active_map.len()] 461 }, 462 LayoutKind::SingleFloat => |_, _, active_map| { 463 let config = &LayoutKind::SingleFloat.config(); 464 active_map 465 .into_iter() 466 .map(|b| (Disposition::Unchanged(config.decoration), b)) 467 .collect() 468 }, 469 LayoutKind::BLSingleFloat => |_, _, active_map| { 470 let config = &LayoutKind::BLSingleFloat.config(); 471 active_map 472 .into_iter() 473 .map(|b| (Disposition::Unchanged(config.decoration), b)) 474 .collect() 475 }, 476 LayoutKind::Center => |region, data, active_map| { 477 let config = &LayoutKind::Center.config(); 478 let (pos, dim) = region.values(); 479 480 let h_comp = Layout::MAX_MAIN_COUNT + 1; 481 let w_ratio: f32 = data.main_factor / 0.95; 482 let h_ratio: f32 = (h_comp - data.main_count) as f32 / h_comp as f32; 483 484 active_map 485 .into_iter() 486 .map(|_| { 487 ( 488 Disposition::Changed( 489 Region { 490 pos, 491 dim, 492 } 493 .from_absolute_inner_center(Dim { 494 w: (dim.w as f32 * w_ratio) as i32, 495 h: (dim.h as f32 * h_ratio) as i32, 496 }), 497 config.decoration, 498 ), 499 true, 500 ) 501 }) 502 .collect() 503 }, 504 LayoutKind::Monocle => |region, _, active_map| { 505 let config = &LayoutKind::Monocle.config(); 506 let (pos, dim) = region.values(); 507 508 active_map 509 .into_iter() 510 .map(|_| { 511 ( 512 Disposition::Changed( 513 Region { 514 pos, 515 dim, 516 }, 517 config.decoration, 518 ), 519 true, 520 ) 521 }) 522 .collect() 523 }, 524 LayoutKind::Paper => |region, data, active_map| { 525 const MIN_W_RATIO: f32 = 0.5; 526 527 let config = &LayoutKind::Paper.config(); 528 let (pos, dim) = region.values(); 529 let n = active_map.len(); 530 531 if n == 1 { 532 return vec![( 533 Disposition::Changed(*region, Decoration::NO_DECORATION), 534 true, 535 )]; 536 } 537 538 let cw = (dim.w as f32 539 * if data.main_factor > MIN_W_RATIO { 540 data.main_factor 541 } else { 542 MIN_W_RATIO 543 }) as i32; 544 545 let w = ((dim.w - cw) as usize / (n - 1)) as i32; 546 let mut after_active = false; 547 548 active_map 549 .into_iter() 550 .enumerate() 551 .map(|(i, active)| { 552 let i = i as i32; 553 554 ( 555 Disposition::Changed( 556 if active { 557 after_active = true; 558 Region::new(pos.x + i * w, pos.y, cw, dim.h) 559 } else { 560 let mut x = pos.x + i * w; 561 562 if after_active { 563 x += cw - w; 564 } 565 566 Region::new(x, pos.y, w, dim.h) 567 }, 568 config.decoration, 569 ), 570 true, 571 ) 572 }) 573 .collect() 574 }, 575 LayoutKind::SPaper => |region, data, active_map| { 576 let mut region = region.clone(); 577 Layout::adjust_for_gap_size(&mut region, data.gap_size, &Zone::MIN_ZONE_DIM); 578 579 (Self::Paper.func())(®ion, data, active_map) 580 }, 581 LayoutKind::Stack => |region, data, active_map| { 582 let (pos, dim) = region.values(); 583 let n = active_map.len(); 584 585 if n == 1 { 586 return vec![( 587 Disposition::Changed(*region, Decoration::NO_DECORATION), 588 true, 589 )]; 590 } 591 592 let (n_main, n_stack) = Self::stack_split(n, data.main_count); 593 let h_stack = if n_stack > 0 { dim.h / n_stack } else { 0 }; 594 let h_main = if n_main > 0 { dim.h / n_main } else { 0 }; 595 596 let div = if data.main_count > 0 { 597 (dim.w as f32 * data.main_factor) as i32 598 } else { 599 0 600 }; 601 602 let config = &LayoutKind::Stack.config(); 603 let main_count = data.main_count as i32; 604 605 active_map 606 .into_iter() 607 .enumerate() 608 .map(|(i, _)| { 609 let i = i as i32; 610 611 ( 612 Disposition::Changed( 613 if i < main_count { 614 Region::new( 615 pos.x, 616 pos.y + (i * h_main), 617 if n_stack == 0 { dim.w } else { div }, 618 h_main, 619 ) 620 } else { 621 Region::new( 622 pos.x + div, 623 pos.y + (i - main_count) * h_stack, 624 dim.w - div, 625 h_stack, 626 ) 627 }, 628 config.decoration, 629 ), 630 true, 631 ) 632 }) 633 .collect() 634 }, 635 LayoutKind::SStack => |region, data, active_map| { 636 let mut region = region.clone(); 637 Layout::adjust_for_gap_size(&mut region, data.gap_size, &Zone::MIN_ZONE_DIM); 638 639 (Self::Stack.func())(®ion, data, active_map) 640 }, 641 LayoutKind::BStack => |region, data, active_map| { 642 let (pos, dim) = region.values(); 643 let n = active_map.len(); 644 645 if n == 1 { 646 return vec![( 647 Disposition::Changed(*region, Decoration::NO_DECORATION), 648 true, 649 )]; 650 } 651 652 let (n_main, n_stack) = Self::stack_split(n, data.main_count); 653 654 let div = if data.main_count > 0 { 655 (dim.w as f32 * data.main_factor) as i32 656 } else { 657 0 658 }; 659 660 let h_main = if n_main > 0 { 661 (if n_stack > 0 { div } else { dim.h }) / n_main 662 } else { 663 0 664 }; 665 666 let w_stack = if n_stack > 0 { dim.w / n_stack } else { 0 }; 667 668 let config = &LayoutKind::Stack.config(); 669 let main_count = data.main_count as i32; 670 671 active_map 672 .into_iter() 673 .enumerate() 674 .map(|(i, _)| { 675 let i = i as i32; 676 677 ( 678 Disposition::Changed( 679 if i < main_count { 680 Region::new(pos.x, pos.y + (i * h_main), dim.w, h_main) 681 } else { 682 Region::new( 683 pos.x + ((i - main_count) * w_stack), 684 pos.y + div, 685 w_stack, 686 dim.h - div, 687 ) 688 }, 689 config.decoration, 690 ), 691 true, 692 ) 693 }) 694 .collect() 695 }, 696 LayoutKind::SBStack => |region, data, active_map| { 697 let mut region = region.clone(); 698 Layout::adjust_for_gap_size(&mut region, data.gap_size, &Zone::MIN_ZONE_DIM); 699 700 (Self::BStack.func())(®ion, data, active_map) 701 }, 702 LayoutKind::Horz => |_region, _data, _active_map| todo!(), 703 LayoutKind::SHorz => |_region, _data, _active_map| todo!(), 704 LayoutKind::Vert => |_region, _data, _active_map| todo!(), 705 LayoutKind::SVert => |_region, _data, _active_map| todo!(), 706 707 #[allow(unreachable_patterns)] 708 _ => unimplemented!("{:?} does not have an associated function", self), 709 } 710 } 711 } 712 713 pub struct Layout { 714 kind: LayoutKind, 715 prev_kind: LayoutKind, 716 data: HashMap<LayoutKind, LayoutData>, 717 } 718 719 impl Layout { 720 #[inline] 721 pub fn new() -> Self { 722 let kind = LayoutKind::Stack; 723 let mut data = HashMap::with_capacity(LayoutKind::COUNT); 724 725 for kind in LayoutKind::iter() { 726 data.insert(kind, kind.default_data()); 727 } 728 729 Self { 730 kind, 731 prev_kind: kind, 732 data, 733 } 734 } 735 736 #[inline] 737 pub fn with_kind(kind: LayoutKind) -> Self { 738 let mut data = HashMap::with_capacity(LayoutKind::COUNT); 739 740 for kind in LayoutKind::iter() { 741 data.insert(kind, kind.default_data()); 742 } 743 744 Self { 745 kind, 746 prev_kind: kind, 747 data, 748 } 749 } 750 751 #[inline] 752 pub fn kind(&self) -> LayoutKind { 753 self.kind 754 } 755 756 #[inline] 757 pub fn prev_kind(&self) -> LayoutKind { 758 self.prev_kind 759 } 760 761 #[inline] 762 pub fn config(&self) -> LayoutConfig { 763 self.kind.config() 764 } 765 766 #[inline] 767 pub fn prev_data(&self) -> &LayoutData { 768 self.data.get(&self.prev_kind).unwrap() 769 } 770 771 #[inline] 772 pub fn data(&self) -> &LayoutData { 773 self.data.get(&self.kind).unwrap() 774 } 775 776 #[inline] 777 pub fn data_mut(&mut self) -> &mut LayoutData { 778 self.data.get_mut(&self.kind).unwrap() 779 } 780 781 #[inline] 782 pub fn default_data(&self) -> LayoutData { 783 self.kind.default_data() 784 } 785 786 #[inline] 787 pub fn set_kind( 788 &mut self, 789 kind: LayoutKind, 790 ) -> Result<LayoutKind, StateChangeError> { 791 if kind == self.kind { 792 return Err(StateChangeError::EarlyStop); 793 } 794 795 self.prev_kind = self.kind; 796 self.kind = kind; 797 798 Ok(self.prev_kind) 799 } 800 801 #[inline] 802 pub fn adjust_for_margin( 803 region: Region, 804 extents: &Extents, 805 ) -> Region { 806 Region { 807 pos: Pos { 808 x: region.pos.x + extents.left, 809 y: region.pos.y + extents.top, 810 }, 811 dim: Dim { 812 w: region.dim.w - extents.left - extents.right, 813 h: region.dim.h - extents.top - extents.bottom, 814 }, 815 } 816 } 817 818 #[inline] 819 pub fn adjust_for_gap_size( 820 region: &mut Region, 821 gap_size: u32, 822 min_dim: &Dim, 823 ) { 824 let gap_size = gap_size as i32; 825 let dim_gap = 2 * gap_size; 826 827 let new_w = region.dim.w - dim_gap; 828 if new_w < min_dim.w { 829 region.pos.x += ((region.dim.w - min_dim.w) as f32 / 2f32) as i32; 830 region.dim.w = min_dim.w; 831 } else { 832 region.dim.w = new_w; 833 region.pos.x += gap_size; 834 } 835 836 let new_h = region.dim.h - dim_gap; 837 if new_h < min_dim.h { 838 region.pos.y += ((region.dim.h - min_dim.h) as f32 / 2f32) as i32; 839 region.dim.h = min_dim.h; 840 } else { 841 region.dim.h = new_h; 842 region.pos.y += gap_size; 843 } 844 } 845 846 #[inline] 847 pub fn adjust_for_border( 848 region: &mut Region, 849 border_width: u32, 850 min_dim: &Dim, 851 ) { 852 let border_padding = 2 * border_width as i32; 853 854 let new_w = region.dim.w - border_padding; 855 region.dim.w = std::cmp::max(min_dim.w, new_w); 856 857 let new_h = region.dim.h - border_padding; 858 region.dim.h = std::cmp::max(min_dim.h, new_h); 859 } 860 } 861 862 impl Default for Layout { 863 fn default() -> Self { 864 Self { 865 kind: LayoutKind::Stack, 866 prev_kind: LayoutKind::Stack, 867 data: HashMap::new(), 868 } 869 } 870 } 871 872 pub trait Apply { 873 fn apply( 874 &self, 875 region: Region, 876 active_map: Vec<bool>, 877 ) -> (PlacementMethod, Vec<(Disposition, bool)>); 878 } 879 880 impl Apply for Layout { 881 #[inline] 882 fn apply( 883 &self, 884 region: Region, 885 active_map: Vec<bool>, 886 ) -> (PlacementMethod, Vec<(Disposition, bool)>) { 887 let config = self.kind.config(); 888 let data = self.data(); 889 890 let region = if config.margin { 891 Self::adjust_for_margin(region, &data.margin) 892 } else { 893 region 894 }; 895 896 ( 897 config.method, 898 (self.kind.func())(®ion, &data, active_map) 899 .into_iter() 900 .map(|(mut disposition, is_visible)| { 901 match disposition { 902 Disposition::Unchanged(_) => {}, 903 Disposition::Changed(ref mut region, decoration) => { 904 if let Some(border) = decoration.border { 905 Self::adjust_for_gap_size( 906 region, 907 border.width, 908 &Zone::MIN_ZONE_DIM, 909 ); 910 } 911 912 if config.gap { 913 Self::adjust_for_gap_size( 914 region, 915 data.gap_size, 916 &Zone::MIN_ZONE_DIM, 917 ); 918 } 919 }, 920 } 921 922 (disposition, is_visible) 923 }) 924 .collect(), 925 ) 926 } 927 } 928 929 impl PartialEq<Self> for Layout { 930 fn eq( 931 &self, 932 other: &Self, 933 ) -> bool { 934 self.kind == other.kind && self.data.get(&self.kind) == other.data.get(&other.kind) 935 } 936 } 937 938 impl Identify for Layout { 939 #[inline(always)] 940 fn id(&self) -> Ident { 941 self.kind as Ident 942 } 943 } 944 945 impl std::fmt::Debug for Layout { 946 fn fmt( 947 &self, 948 f: &mut std::fmt::Formatter<'_>, 949 ) -> std::fmt::Result { 950 f.debug_struct("Layout") 951 .field("kind", &self.kind) 952 .field("prev_kind", &self.prev_kind) 953 .field("data", &self.data.get(&self.kind)) 954 .finish() 955 } 956 }