1use super::LengthPercentage;
4use crate::style_helpers::{
5 FromFr, FromLength, FromPercent, TaffyAuto, TaffyFitContent, TaffyMaxContent, TaffyMinContent, TaffyZero,
6};
7
8mod compat {
12 #![allow(unsafe_code)]
13 #![allow(unknown_lints)]
14 #![allow(unnecessary_transmutes)]
15
16 pub const fn f32_to_bits(val: f32) -> u32 {
18 unsafe { core::mem::transmute(val) }
20 }
21 pub const fn f32_from_bits(v: u32) -> f32 {
23 unsafe { core::mem::transmute(v) }
25 }
26
27 #[inline(always)]
29 #[cfg(all(target_pointer_width = "64", feature = "strict_provenance"))]
30 pub fn tag_ptr(ptr: *const (), tag: usize) -> *const () {
31 ptr.map_addr(|a| a | tag)
32 }
33
34 #[inline(always)]
36 #[cfg(all(target_pointer_width = "64", not(feature = "strict_provenance")))]
37 pub fn tag_ptr(ptr: *const (), tag: usize) -> *const () {
38 (ptr as usize | tag) as *const ()
39 }
40
41 #[inline(always)]
43 #[cfg(all(target_pointer_width = "64", feature = "strict_provenance"))]
44 pub fn untag_ptr(ptr: *const (), mask: usize) -> *const () {
45 ptr.map_addr(|a| a & !mask)
46 }
47
48 #[inline(always)]
50 #[cfg(all(target_pointer_width = "64", not(feature = "strict_provenance")))]
51 pub fn untag_ptr(ptr: *const (), mask: usize) -> *const () {
52 (ptr as usize & !mask) as *const ()
53 }
54}
55
56#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))]
57std::compile_error!("Taffy only supports targets with a pointer width of 32 or 64 bits");
58
59#[cfg(target_pointer_width = "64")]
61mod inner {
62 use super::compat::{f32_from_bits, f32_to_bits, tag_ptr, untag_ptr};
63
64 const TAG_MASK: usize = 0b11111111;
66 const CALC_TAG_MASK: usize = 0b111;
68
69 #[derive(Copy, Clone, Debug, PartialEq)]
74 pub(super) struct CompactLengthInner {
75 tagged_ptr: *const (),
77 }
78 impl CompactLengthInner {
79 #[inline(always)]
81 pub(super) fn from_ptr(ptr: *const (), tag: usize) -> Self {
82 let tagged_ptr = tag_ptr(ptr, tag);
83 Self { tagged_ptr }
84 }
85
86 #[inline(always)]
88 pub(super) const fn from_val(val: f32, tag: usize) -> Self {
89 let tagged_ptr = (((f32_to_bits(val) as usize) << 32) | tag) as *const ();
90 Self { tagged_ptr }
91 }
92
93 #[inline(always)]
95 pub(super) const fn from_tag(tag: usize) -> Self {
96 let tagged_ptr = tag as *const ();
97 Self { tagged_ptr }
98 }
99
100 #[inline(always)]
102 #[cfg(feature = "calc")]
103 pub(super) fn calc_tag(self) -> usize {
104 (self.tagged_ptr as usize) & CALC_TAG_MASK
105 }
106
107 #[inline(always)]
109 pub(super) fn tag(self) -> usize {
110 (self.tagged_ptr as usize) & TAG_MASK
111 }
112
113 #[inline(always)]
115 pub(super) fn ptr(self) -> *const () {
116 untag_ptr(self.tagged_ptr, CALC_TAG_MASK)
117 }
118
119 #[inline(always)]
121 pub(super) fn value(self) -> f32 {
122 f32_from_bits((self.tagged_ptr as usize >> 32) as u32)
123 }
124
125 #[inline(always)]
127 #[cfg(feature = "serde")]
128 pub(super) fn serialized(self) -> u64 {
129 (self.tagged_ptr as usize as u64).rotate_left(32)
130 }
131
132 #[inline(always)]
134 #[cfg(feature = "serde")]
135 pub(super) fn from_serialized(value: u64) -> Self {
136 Self { tagged_ptr: value.rotate_right(32) as usize as *const () }
137 }
138 }
139}
140
141#[cfg(target_pointer_width = "32")]
143mod inner {
144 use super::compat::{f32_from_bits, f32_to_bits};
145
146 #[derive(Copy, Clone, Debug, PartialEq)]
150 pub(super) struct CompactLengthInner {
151 tag: usize,
153 ptr: *const (),
155 }
156
157 impl CompactLengthInner {
158 #[inline(always)]
160 pub(super) fn from_ptr(ptr: *const (), tag: usize) -> Self {
161 Self { ptr, tag }
162 }
163
164 #[inline(always)]
166 pub(super) const fn from_val(val: f32, tag: usize) -> Self {
167 Self { ptr: f32_to_bits(val) as usize as *const (), tag }
168 }
169
170 #[inline(always)]
172 pub(super) const fn from_tag(tag: usize) -> Self {
173 Self { ptr: 0 as *const (), tag }
174 }
175
176 #[inline(always)]
178 #[cfg(feature = "calc")]
179 pub(super) fn calc_tag(self) -> usize {
180 self.tag
181 }
182
183 #[inline(always)]
185 pub(super) fn tag(self) -> usize {
186 self.tag
187 }
188
189 #[inline(always)]
191 pub(super) fn ptr(self) -> *const () {
192 self.ptr
193 }
194
195 #[inline(always)]
197 pub(super) fn value(self) -> f32 {
198 f32_from_bits(self.ptr as u32)
199 }
200
201 #[inline(always)]
203 #[cfg(feature = "serde")]
204 pub(super) fn serialized(self) -> u64 {
205 (self.tag as u64) << 32 | (self.ptr as u64)
206 }
207
208 #[inline(always)]
210 #[cfg(feature = "serde")]
211 pub(super) fn from_serialized(value: u64) -> Self {
212 Self { tag: (value >> 32) as usize, ptr: (value & 0xFFFFFFFF) as usize as *const () }
213 }
214 }
215}
216
217use inner::CompactLengthInner;
218
219#[derive(Copy, Clone, PartialEq, Debug)]
221#[repr(transparent)]
222pub struct CompactLength(CompactLengthInner);
223
224impl CompactLength {
244 pub const NON_POINTER_BIT: usize = 0b0001;
246 pub const KEYWORD_BIT: usize = 0b0010;
248 pub const PERCENTAGE_BIT: usize = 0b0100;
250 pub const SIZING_KEYWORD_BIT: usize = 0b1000;
252
253 #[cfg(feature = "calc")]
255 pub const CALC_TAG: usize = 0b0000_0100;
256 #[cfg(feature = "calc")]
258 pub const FIT_CONTENT_CALC_TAG: usize = 0b0000_0110;
259 pub const LENGTH_TAG: usize = 0b0000_0001;
261 pub const PERCENT_TAG: usize = 0b0000_0101;
263 pub const AUTO_TAG: usize = 0b0000_0011;
265 pub const FR_TAG: usize = 0b0001_0011;
267 pub const CONTENT_TAG: usize = 0b0010_0011;
269 pub const MIN_CONTENT_TAG: usize = 0b0000_1011;
271 pub const MAX_CONTENT_TAG: usize = 0b0001_1011;
273 pub const FIT_CONTENT_PX_TAG: usize = 0b0010_1011;
275 pub const FIT_CONTENT_KEYWORD_TAG: usize = 0b0011_1011;
277 pub const STRETCH_TAG: usize = 0b0100_1011;
279 pub const FIT_CONTENT_PERCENT_TAG: usize = 0b0000_1111;
281}
282
283impl CompactLength {
284 #[inline(always)]
287 pub const fn length(val: f32) -> Self {
288 Self(CompactLengthInner::from_val(val, Self::LENGTH_TAG))
289 }
290
291 #[inline(always)]
295 pub const fn percent(val: f32) -> Self {
296 Self(CompactLengthInner::from_val(val, Self::PERCENT_TAG))
297 }
298
299 #[inline]
304 #[cfg(feature = "calc")]
305 pub fn calc(ptr: *const ()) -> Self {
306 assert_ne!(ptr as u64, 0);
307 assert_eq!(ptr as u64 & 0b111, 0);
308 Self(CompactLengthInner::from_ptr(ptr, Self::CALC_TAG))
309 }
310
311 #[inline]
316 #[cfg(feature = "calc")]
317 pub fn fit_content_calc(ptr: *const ()) -> Self {
318 assert_ne!(ptr as u64, 0);
319 assert_eq!(ptr as u64 & 0b111, 0);
320 Self(CompactLengthInner::from_ptr(ptr, Self::FIT_CONTENT_CALC_TAG))
321 }
322
323 #[inline(always)]
326 pub const fn auto() -> Self {
327 Self(CompactLengthInner::from_tag(Self::AUTO_TAG))
328 }
329
330 #[inline(always)]
334 pub const fn fr(val: f32) -> Self {
335 Self(CompactLengthInner::from_val(val, Self::FR_TAG))
336 }
337
338 #[inline(always)]
341 pub const fn min_content() -> Self {
342 Self(CompactLengthInner::from_tag(Self::MIN_CONTENT_TAG))
343 }
344
345 #[inline(always)]
348 pub const fn max_content() -> Self {
349 Self(CompactLengthInner::from_tag(Self::MAX_CONTENT_TAG))
350 }
351
352 #[inline(always)]
362 pub const fn fit_content_px(limit: f32) -> Self {
363 Self(CompactLengthInner::from_val(limit, Self::FIT_CONTENT_PX_TAG))
364 }
365
366 #[inline(always)]
376 pub const fn fit_content_percent(limit: f32) -> Self {
377 Self(CompactLengthInner::from_val(limit, Self::FIT_CONTENT_PERCENT_TAG))
378 }
379
380 #[inline(always)]
387 pub const fn fit_content_keyword() -> Self {
388 Self(CompactLengthInner::from_tag(Self::FIT_CONTENT_KEYWORD_TAG))
389 }
390
391 #[inline(always)]
395 pub const fn stretch() -> Self {
396 Self(CompactLengthInner::from_tag(Self::STRETCH_TAG))
397 }
398
399 #[inline(always)]
404 pub const fn content() -> Self {
405 Self(CompactLengthInner::from_tag(Self::CONTENT_TAG))
406 }
407
408 #[inline(always)]
410 pub fn tag(self) -> usize {
411 self.0.tag()
412 }
413
414 #[inline(always)]
417 pub fn value(self) -> f32 {
418 self.0.value()
419 }
420
421 #[inline(always)]
423 #[cfg(feature = "calc")]
424 pub fn calc_value(self) -> *const () {
425 self.0.ptr()
426 }
427
428 #[inline(always)]
430 #[cfg(feature = "calc")]
431 pub fn is_plain_calc(self) -> bool {
432 self.0.calc_tag() & (Self::NON_POINTER_BIT | Self::KEYWORD_BIT) == 0
433 }
434
435 #[inline(always)]
437 pub fn is_fit_content_calc(self) -> bool {
438 self.tag() & (Self::NON_POINTER_BIT | Self::KEYWORD_BIT) == Self::KEYWORD_BIT
439 }
440
441 #[inline(always)]
444 pub fn has_calc(self) -> bool {
445 self.tag() & Self::NON_POINTER_BIT == 0
446 }
447
448 #[inline(always)]
450 pub fn is_zero(self) -> bool {
451 self.0 == Self::ZERO.0
452 }
453
454 #[inline(always)]
456 pub fn is_length_or_percentage(self) -> bool {
457 self.tag() & (Self::NON_POINTER_BIT | Self::KEYWORD_BIT) == Self::NON_POINTER_BIT
458 }
459
460 #[inline(always)]
463 pub fn is_length_percentage_or_calc(self) -> bool {
464 self.tag() & Self::KEYWORD_BIT == 0
465 }
466
467 #[inline(always)]
469 pub fn is_auto(self) -> bool {
470 self.tag() == Self::AUTO_TAG
471 }
472
473 #[inline(always)]
475 pub fn is_content(self) -> bool {
476 self.tag() == Self::CONTENT_TAG
477 }
478
479 #[inline(always)]
481 pub fn is_min_content(self) -> bool {
482 matches!(self.tag(), Self::MIN_CONTENT_TAG)
483 }
484
485 #[inline(always)]
487 pub fn is_max_content(self) -> bool {
488 matches!(self.tag(), Self::MAX_CONTENT_TAG)
489 }
490
491 #[inline(always)]
493 pub fn is_fit_content(self) -> bool {
494 matches!(self.tag(), Self::FIT_CONTENT_PX_TAG | Self::FIT_CONTENT_PERCENT_TAG) || self.is_fit_content_calc()
495 }
496
497 #[inline(always)]
499 pub fn is_sizing_keyword(self) -> bool {
500 const MASK: usize =
501 CompactLength::NON_POINTER_BIT | CompactLength::KEYWORD_BIT | CompactLength::SIZING_KEYWORD_BIT;
502 self.tag() & MASK == MASK || self.is_fit_content_calc()
503 }
504
505 #[inline(always)]
507 pub fn is_max_or_fit_content(self) -> bool {
508 matches!(self.tag(), Self::MAX_CONTENT_TAG | Self::FIT_CONTENT_PX_TAG | Self::FIT_CONTENT_PERCENT_TAG)
509 || self.is_fit_content_calc()
510 }
511
512 #[inline(always)]
516 pub fn is_max_content_alike(&self) -> bool {
517 matches!(
518 self.tag(),
519 CompactLength::AUTO_TAG
520 | CompactLength::MAX_CONTENT_TAG
521 | CompactLength::FIT_CONTENT_PX_TAG
522 | CompactLength::FIT_CONTENT_PERCENT_TAG
523 ) || self.is_fit_content_calc()
524 }
525
526 #[inline(always)]
528 pub fn is_min_or_max_content(&self) -> bool {
529 matches!(self.tag(), Self::MIN_CONTENT_TAG | Self::MAX_CONTENT_TAG)
530 }
531
532 #[inline(always)]
534 pub fn is_intrinsic(self) -> bool {
535 matches!(
536 self.tag(),
537 Self::AUTO_TAG
538 | Self::MIN_CONTENT_TAG
539 | Self::MAX_CONTENT_TAG
540 | Self::FIT_CONTENT_PX_TAG
541 | Self::FIT_CONTENT_PERCENT_TAG
542 ) || self.is_fit_content_calc()
543 }
544
545 #[inline(always)]
547 pub fn is_fr(self) -> bool {
548 self.tag() == Self::FR_TAG
549 }
550
551 #[inline(always)]
553 pub fn uses_percentage(self) -> bool {
554 self.tag() & Self::PERCENTAGE_BIT != 0
555 }
556
557 #[inline(always)]
560 pub fn resolved_percentage_size(
561 self,
562 parent_size: f32,
563 calc_resolver: impl Fn(*const (), f32) -> f32,
564 ) -> Option<f32> {
565 match self.tag() {
566 CompactLength::PERCENT_TAG => Some(self.value() * parent_size),
567 #[cfg(feature = "calc")]
568 _ if self.is_plain_calc() => Some(calc_resolver(self.0.ptr(), parent_size)),
569 _ => None,
570 }
571 }
572}
573
574impl TaffyZero for CompactLength {
575 const ZERO: Self = Self::length(0.0);
576}
577impl TaffyAuto for CompactLength {
578 const AUTO: Self = Self::auto();
579}
580impl TaffyMinContent for CompactLength {
581 const MIN_CONTENT: Self = Self::min_content();
582}
583impl TaffyMaxContent for CompactLength {
584 const MAX_CONTENT: Self = Self::max_content();
585}
586impl FromLength for CompactLength {
587 fn from_length<Input: Into<f64> + Copy>(value: Input) -> Self {
588 Self::length(value.into() as f32)
589 }
590}
591impl FromPercent for CompactLength {
592 fn from_percent<Input: Into<f64> + Copy>(value: Input) -> Self {
593 Self::percent(value.into() as f32)
594 }
595}
596impl FromFr for CompactLength {
597 fn from_fr<Input: Into<f64> + Copy>(value: Input) -> Self {
598 Self::fr(value.into() as f32)
599 }
600}
601impl TaffyFitContent for CompactLength {
602 fn fit_content(lp: LengthPercentage) -> Self {
603 let value = lp.0.value();
604 match lp.0.tag() {
605 Self::LENGTH_TAG => Self::fit_content_px(value),
606 Self::PERCENT_TAG => Self::fit_content_percent(value),
607 #[cfg(feature = "calc")]
608 _ if lp.0.is_plain_calc() => Self::fit_content_calc(lp.0.calc_value()),
609 _ => unreachable!(),
610 }
611 }
612}
613
614#[cfg(feature = "serde")]
615impl serde::Serialize for CompactLength {
616 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
617 where
618 S: serde::Serializer,
619 {
620 #[cfg(feature = "calc")]
621 {
622 if self.has_calc() {
623 Err(serde::ser::Error::custom("Cannot serialize Calc value"))
624 } else {
625 serializer.serialize_u64(self.0.serialized())
626 }
627 }
628
629 #[cfg(not(feature = "calc"))]
630 serializer.serialize_u64(self.0.serialized())
631 }
632}
633
634#[cfg(feature = "serde")]
635impl<'de> serde::Deserialize<'de> for CompactLength {
636 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
637 where
638 D: serde::Deserializer<'de>,
639 {
640 let bits: u64 = u64::deserialize(deserializer)?;
641 let value = Self(CompactLengthInner::from_serialized(bits));
642 if matches!(
645 value.tag(),
646 CompactLength::LENGTH_TAG
647 | CompactLength::PERCENT_TAG
648 | CompactLength::AUTO_TAG
649 | CompactLength::MIN_CONTENT_TAG
650 | CompactLength::MAX_CONTENT_TAG
651 | CompactLength::FIT_CONTENT_KEYWORD_TAG
652 | CompactLength::FIT_CONTENT_PX_TAG
653 | CompactLength::FIT_CONTENT_PERCENT_TAG
654 | CompactLength::STRETCH_TAG
655 | CompactLength::CONTENT_TAG
656 | CompactLength::FR_TAG
657 ) {
658 Ok(value)
659 } else {
660 Err(serde::de::Error::custom("Cannot deserialize Calc value"))
661 }
662 }
663}
664
665#[cfg(test)]
666mod tests {
667 use super::{CompactLength, CompactLengthInner};
668
669 impl CompactLength {
670 fn from_raw_tag(tag: usize) -> Self {
671 Self(CompactLengthInner::from_tag(tag))
672 }
673 }
674
675 const NON_PERCENTAGE_TAGS: &[usize] = &[
676 CompactLength::LENGTH_TAG,
677 CompactLength::AUTO_TAG,
678 CompactLength::FR_TAG,
679 CompactLength::MIN_CONTENT_TAG,
680 CompactLength::MAX_CONTENT_TAG,
681 CompactLength::FIT_CONTENT_PX_TAG,
682 CompactLength::FIT_CONTENT_KEYWORD_TAG,
683 CompactLength::STRETCH_TAG,
684 CompactLength::CONTENT_TAG,
685 ];
686 const PERCENTAGE_TAGS: &[usize] = &[CompactLength::PERCENT_TAG, CompactLength::FIT_CONTENT_PERCENT_TAG];
687
688 #[test]
689 fn tags_are_unique_and_fit_in_a_byte() {
690 let mut all: Vec<usize> = NON_PERCENTAGE_TAGS.iter().chain(PERCENTAGE_TAGS).copied().collect();
691 #[cfg(feature = "calc")]
692 all.push(CompactLength::CALC_TAG);
693 #[cfg(feature = "calc")]
694 all.push(CompactLength::FIT_CONTENT_CALC_TAG);
695 assert!(all.iter().all(|tag| *tag <= 0xFF));
696 all.sort_unstable();
697 all.dedup();
698 assert_eq!(all.len(), NON_PERCENTAGE_TAGS.len() + PERCENTAGE_TAGS.len() + 2 * cfg!(feature = "calc") as usize);
699 }
700
701 #[test]
702 fn non_pointer_tags_have_non_pointer_bit_set() {
703 for tag in NON_PERCENTAGE_TAGS.iter().chain(PERCENTAGE_TAGS) {
704 assert_ne!(tag & CompactLength::NON_POINTER_BIT, 0, "tag {tag:#010b}");
705 }
706 #[cfg(feature = "calc")]
707 assert_eq!(CompactLength::CALC_TAG & CompactLength::NON_POINTER_BIT, 0);
708 }
709
710 #[test]
711 fn keyword_bits_match_predicates() {
712 let all = NON_PERCENTAGE_TAGS.iter().chain(PERCENTAGE_TAGS).map(|tag| CompactLength::from_raw_tag(*tag));
713 for value in all {
714 let tag = value.tag();
715 let is_plain = matches!(tag, CompactLength::LENGTH_TAG | CompactLength::PERCENT_TAG);
716 assert_eq!(tag & CompactLength::KEYWORD_BIT == 0, is_plain, "tag {tag:#010b}");
717 assert_eq!(value.is_length_or_percentage(), is_plain, "tag {tag:#010b}");
718 let is_sizing_keyword = matches!(
719 tag,
720 CompactLength::MIN_CONTENT_TAG
721 | CompactLength::MAX_CONTENT_TAG
722 | CompactLength::FIT_CONTENT_KEYWORD_TAG
723 | CompactLength::FIT_CONTENT_PX_TAG
724 | CompactLength::FIT_CONTENT_PERCENT_TAG
725 | CompactLength::STRETCH_TAG
726 );
727 assert_eq!(value.is_sizing_keyword(), is_sizing_keyword, "tag {tag:#010b}");
728 }
729 #[cfg(feature = "calc")]
730 {
731 assert_eq!(CompactLength::CALC_TAG & CompactLength::KEYWORD_BIT, 0);
732 assert_ne!(CompactLength::FIT_CONTENT_CALC_TAG & CompactLength::KEYWORD_BIT, 0);
733 assert_eq!(CompactLength::FIT_CONTENT_CALC_TAG & CompactLength::NON_POINTER_BIT, 0);
734 assert_ne!(CompactLength::FIT_CONTENT_CALC_TAG & CompactLength::PERCENTAGE_BIT, 0);
735 }
736 }
737
738 #[test]
739 fn percentage_bit_matches_uses_percentage() {
740 for tag in NON_PERCENTAGE_TAGS {
741 assert_eq!(tag & CompactLength::PERCENTAGE_BIT, 0, "tag {tag:#010b}");
742 }
743 for tag in PERCENTAGE_TAGS {
744 assert_ne!(tag & CompactLength::PERCENTAGE_BIT, 0, "tag {tag:#010b}");
745 }
746 #[cfg(feature = "calc")]
747 assert_ne!(CompactLength::CALC_TAG & CompactLength::PERCENTAGE_BIT, 0);
748
749 assert!(!CompactLength::length(10.0).uses_percentage());
750 assert!(!CompactLength::auto().uses_percentage());
751 assert!(!CompactLength::fr(1.0).uses_percentage());
752 assert!(!CompactLength::min_content().uses_percentage());
753 assert!(!CompactLength::max_content().uses_percentage());
754 assert!(!CompactLength::fit_content_px(10.0).uses_percentage());
755 assert!(!CompactLength::fit_content_keyword().uses_percentage());
756 assert!(!CompactLength::stretch().uses_percentage());
757 assert!(!CompactLength::content().uses_percentage());
758 assert!(CompactLength::percent(0.5).uses_percentage());
759 assert!(CompactLength::fit_content_percent(0.5).uses_percentage());
760 }
761
762 #[test]
763 #[cfg(feature = "calc")]
764 fn fit_content_calc_round_trips_pointer() {
765 let boxed = Box::new(0u64);
766 let ptr = &*boxed as *const u64 as *const ();
767 let value = CompactLength::fit_content_calc(ptr);
768 assert!(value.is_fit_content_calc());
769 assert!(value.has_calc());
770 assert!(!value.is_plain_calc());
771 assert!(value.is_fit_content());
772 assert!(value.is_sizing_keyword());
773 assert!(value.is_intrinsic());
774 assert!(value.is_max_or_fit_content());
775 assert!(value.is_max_content_alike());
776 assert!(value.uses_percentage());
777 assert!(!value.is_length_or_percentage());
778 assert_eq!(value.calc_value(), ptr);
779
780 let calc = CompactLength::calc(ptr);
781 assert!(calc.is_plain_calc());
782 assert!(calc.has_calc());
783 assert!(!calc.is_fit_content_calc());
784 assert!(!calc.is_fit_content());
785 assert!(!calc.is_sizing_keyword());
786 }
787
788 #[test]
789 fn calc_round_trips_pointer() {
790 let boxed = Box::new(42u64);
791 let ptr = &*boxed as *const u64 as *const ();
792 let value = CompactLength::calc(ptr);
793 assert!(value.is_plain_calc());
794 assert!(value.uses_percentage());
795 assert!(!value.is_length_or_percentage());
796 assert!(!value.is_auto());
797 assert!(!value.is_intrinsic());
798 assert_eq!(value.calc_value(), ptr);
799 }
800}