diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-06-12 17:45:52 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-06-12 20:51:31 +0200 |
| commit | 7660978ee5d842648e244e2972273264d94ca37b (patch) | |
| tree | 74e1c8bc578afa616ddcd6c4c9e79c3c3d311d78 /src/frame.rs | |
| parent | 6e3b1a2c80428d581d00b9d65e1c45401df2e210 (diff) | |
Move `Arc` into `Frame`
Diffstat (limited to 'src/frame.rs')
| -rw-r--r-- | src/frame.rs | 182 |
1 files changed, 73 insertions, 109 deletions
diff --git a/src/frame.rs b/src/frame.rs index 628d8c5b..6855e7ac 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -11,7 +11,7 @@ use crate::geom::{ }; use crate::image::ImageId; use crate::library::text::Lang; -use crate::util::{EcoString, MaybeShared}; +use crate::util::EcoString; /// A finished layout with elements at fixed positions. #[derive(Default, Clone, Eq, PartialEq)] @@ -24,7 +24,7 @@ pub struct Frame { /// The semantic role of the frame. role: Option<Role>, /// The elements composing this layout. - elements: Vec<(Point, Element)>, + elements: Arc<Vec<(Point, Element)>>, } /// Accessors and setters. @@ -39,7 +39,7 @@ impl Frame { size, baseline: None, role: None, - elements: vec![], + elements: Arc::new(vec![]), } } @@ -92,7 +92,7 @@ impl Frame { /// Recover the text inside of the frame and its children. pub fn text(&self) -> EcoString { let mut text = EcoString::new(); - for (_, element) in &self.elements { + for (_, element) in self.elements() { match element { Element::Text(content) => { for glyph in &content.glyphs { @@ -117,59 +117,92 @@ impl Frame { /// Add an element at a position in the foreground. pub fn push(&mut self, pos: Point, element: Element) { - self.elements.push((pos, element)); - } - - /// Insert an element at the given layer in the frame. - /// - /// This panics if the layer is greater than the number of layers present. - #[track_caller] - pub fn insert(&mut self, layer: usize, pos: Point, element: Element) { - self.elements.insert(layer, (pos, element)); + Arc::make_mut(&mut self.elements).push((pos, element)); } /// Add a frame. /// /// Automatically decides whether to inline the frame or to include it as a /// group based on the number of elements in the frame. - pub fn push_frame(&mut self, pos: Point, frame: impl FrameRepr) { - if (self.elements.is_empty() || frame.as_ref().is_light()) - && frame.as_ref().role().map_or(true, Role::is_weak) - { - frame.inline(self, self.layer(), pos); + pub fn push_frame(&mut self, pos: Point, frame: Frame) { + if self.should_inline(&frame) { + self.inline(self.layer(), pos, frame); } else { - self.elements.push((pos, Element::Group(Group::new(frame.share())))); + self.push(pos, Element::Group(Group::new(frame))); } } + /// Insert an element at the given layer in the frame. + /// + /// This panics if the layer is greater than the number of layers present. + #[track_caller] + pub fn insert(&mut self, layer: usize, pos: Point, element: Element) { + Arc::make_mut(&mut self.elements).insert(layer, (pos, element)); + } + /// Add an element at a position in the background. pub fn prepend(&mut self, pos: Point, element: Element) { - self.elements.insert(0, (pos, element)); + Arc::make_mut(&mut self.elements).insert(0, (pos, element)); } /// Add multiple elements at a position in the background. - pub fn prepend_multiple<I>(&mut self, insert: I) + pub fn prepend_multiple<I>(&mut self, elements: I) where I: IntoIterator<Item = (Point, Element)>, { - self.elements.splice(0 .. 0, insert); + Arc::make_mut(&mut self.elements).splice(0 .. 0, elements); } /// Add a frame at a position in the background. - pub fn prepend_frame(&mut self, pos: Point, frame: impl FrameRepr) { - if (self.elements.is_empty() || frame.as_ref().is_light()) - && frame.as_ref().role().map_or(true, Role::is_weak) - { - frame.inline(self, 0, pos); + pub fn prepend_frame(&mut self, pos: Point, frame: Frame) { + if self.should_inline(&frame) { + self.inline(0, pos, frame); } else { - self.elements - .insert(0, (pos, Element::Group(Group::new(frame.share())))); + self.prepend(pos, Element::Group(Group::new(frame))); } } - /// Whether the frame has comparatively few elements. - fn is_light(&self) -> bool { - self.elements.len() <= 5 + /// Whether the given frame should be inlined. + pub fn should_inline(&self, frame: &Frame) -> bool { + (self.elements.is_empty() || frame.elements.len() <= 5) + && frame.role().map_or(true, |role| role.is_weak()) + } + + /// Inline a frame at the given layer. + pub fn inline(&mut self, layer: usize, pos: Point, frame: Frame) { + // Try to just reuse the elements. + if pos.is_zero() && self.elements.is_empty() { + self.elements = frame.elements; + return; + } + + // Try to copy the elements without adjusting the positioned. + // Also try to reuse the elements if the Arc isn't shared. + let range = layer .. layer; + if pos.is_zero() { + let sink = Arc::make_mut(&mut self.elements); + match Arc::try_unwrap(frame.elements) { + Ok(elements) => { + sink.splice(range, elements); + } + Err(arc) => { + sink.splice(range, arc.iter().cloned()); + } + } + return; + } + + // We must adjust the element positioned. + // But still try to reuse the elements if the Arc isn't shared. + let sink = Arc::make_mut(&mut self.elements); + match Arc::try_unwrap(frame.elements) { + Ok(elements) => { + sink.splice(range, elements.into_iter().map(|(p, e)| (p + pos, e))); + } + Err(arc) => { + sink.splice(range, arc.iter().cloned().map(|(p, e)| (p + pos, e))); + } + } } } @@ -177,7 +210,7 @@ impl Frame { impl Frame { /// Remove all elements from the frame. pub fn clear(&mut self) { - self.elements.clear(); + self.elements = Arc::new(vec![]); } /// Resize the frame to a new size, distributing new space according to the @@ -199,7 +232,7 @@ impl Frame { if let Some(baseline) = &mut self.baseline { *baseline += offset.y; } - for (point, _) in &mut self.elements { + for (point, _) in Arc::make_mut(&mut self.elements) { *point += offset; } } @@ -207,7 +240,7 @@ impl Frame { /// Apply the given role to the frame if it doesn't already have one. pub fn apply_role(&mut self, role: Role) { - if self.role.map_or(true, Role::is_weak) { + if self.role.map_or(true, |prev| prev.is_weak() && !role.is_weak()) { self.role = Some(role); } } @@ -232,8 +265,9 @@ impl Frame { where F: FnOnce(&mut Group), { - let mut wrapper = Frame { elements: vec![], ..*self }; - let mut group = Group::new(Arc::new(std::mem::take(self))); + let mut wrapper = Frame::new(self.size); + wrapper.baseline = self.baseline; + let mut group = Group::new(std::mem::take(self)); f(&mut group); wrapper.push(Point::zero(), Element::Group(group)); *self = wrapper; @@ -252,76 +286,6 @@ impl Debug for Frame { } } -impl AsRef<Frame> for Frame { - fn as_ref(&self) -> &Frame { - self - } -} - -/// A representational form of a frame (owned, shared or maybe shared). -pub trait FrameRepr: AsRef<Frame> { - /// Transform into a shared representation. - fn share(self) -> Arc<Frame>; - - /// Inline `self` into the sink frame. - fn inline(self, sink: &mut Frame, layer: usize, offset: Point); -} - -impl FrameRepr for Frame { - fn share(self) -> Arc<Frame> { - Arc::new(self) - } - - fn inline(self, sink: &mut Frame, layer: usize, offset: Point) { - if offset.is_zero() { - if sink.elements.is_empty() { - sink.elements = self.elements; - } else { - sink.elements.splice(layer .. layer, self.elements); - } - } else { - sink.elements.splice( - layer .. layer, - self.elements.into_iter().map(|(p, e)| (p + offset, e)), - ); - } - } -} - -impl FrameRepr for Arc<Frame> { - fn share(self) -> Arc<Frame> { - self - } - - fn inline(self, sink: &mut Frame, layer: usize, offset: Point) { - match Arc::try_unwrap(self) { - Ok(frame) => frame.inline(sink, layer, offset), - Err(rc) => { - sink.elements.splice( - layer .. layer, - rc.elements.iter().cloned().map(|(p, e)| (p + offset, e)), - ); - } - } - } -} - -impl FrameRepr for MaybeShared<Frame> { - fn share(self) -> Arc<Frame> { - match self { - Self::Owned(owned) => owned.share(), - Self::Shared(shared) => shared.share(), - } - } - - fn inline(self, sink: &mut Frame, layer: usize, offset: Point) { - match self { - Self::Owned(owned) => owned.inline(sink, layer, offset), - Self::Shared(shared) => shared.inline(sink, layer, offset), - } - } -} - /// The building block frames are composed of. #[derive(Clone, Eq, PartialEq)] pub enum Element { @@ -357,7 +321,7 @@ impl Debug for Element { #[derive(Clone, Eq, PartialEq)] pub struct Group { /// The group's frame. - pub frame: Arc<Frame>, + pub frame: Frame, /// A transformation to apply to the group. pub transform: Transform, /// Whether the frame should be a clipping boundary. @@ -366,7 +330,7 @@ pub struct Group { impl Group { /// Create a new group with default settings. - pub fn new(frame: Arc<Frame>) -> Self { + pub fn new(frame: Frame) -> Self { Self { frame, transform: Transform::identity(), |
