Simplify compiled path data structure

Use two arrays, one for events and one for coordinates. That simplifies
the code generator and the generated code, and it also provides for
a more compact memory representation.
This commit is contained in:
Simon Hausmann 2020-07-10 10:17:02 +02:00
parent 264b1f650f
commit 4b6e549b96
7 changed files with 254 additions and 313 deletions

View file

@ -8,12 +8,8 @@ namespace sixtyfps {
using internal::types::PathArcTo;
using internal::types::PathElement;
using internal::types::PathEvent;
using internal::types::PathEventBegin;
using internal::types::PathEventCubic;
using internal::types::PathEventEnd;
using internal::types::PathEventLine;
using internal::types::PathEventQuadratic;
using internal::types::PathLineTo;
using internal::types::Point;
struct PathElements
{
@ -26,8 +22,9 @@ public:
{
}
PathElements(const PathEvent *firstEvent, size_t count)
: data(Data::PathEvents(events_from_array(firstEvent, count)))
PathElements(const PathEvent *firstEvent, size_t event_count, const Point *firstCoordinate,
size_t coordinate_count)
: data(events_from_array(firstEvent, event_count, firstCoordinate, coordinate_count))
{
}
@ -40,11 +37,16 @@ private:
return tmp;
}
static SharedArray<PathEvent> events_from_array(const PathEvent *firstEvent, size_t count)
static internal::types::PathElements events_from_array(const PathEvent *firstEvent,
size_t event_count,
const Point *firstCoordinate,
size_t coordinate_count)
{
SharedArray<PathEvent> tmp;
sixtyfps_new_path_events(&tmp, firstEvent, count);
return tmp;
SharedArray<PathEvent> events;
SharedArray<Point> coordinates;
sixtyfps_new_path_events(&events, &coordinates, firstEvent, event_count, firstCoordinate,
coordinate_count);
return Data::PathEvents(events, coordinates);
}
using Data = internal::types::PathElements;

View file

@ -1,10 +1,7 @@
use core::cell::RefCell;
use neon::prelude::*;
use sixtyfps_compilerlib::typeregister::Type;
use sixtyfps_corelib::abi::datastructures::{
PathArcTo, PathElement, PathEvent, PathEventBegin, PathEventCubic, PathEventEnd, PathEventLine,
PathEventQuadratic, PathLineTo, Resource,
};
use sixtyfps_corelib::abi::datastructures::{PathArcTo, PathElement, PathLineTo, Resource};
use sixtyfps_corelib::{ComponentRefPin, EvaluationContext};
use std::rc::Rc;
@ -235,79 +232,7 @@ fn to_js_value<'cx>(
}
js_array.as_value(cx)
} else {
let events_iter = elements.events_iter().unwrap();
let js_array = JsArray::new(cx, events_iter.len() as _);
for (i, event) in events_iter.enumerate() {
let element_object = JsObject::new(cx);
match event {
PathEvent::Begin(PathEventBegin { x, y }) => {
set_string_property(cx, &element_object, "type", "event_begin")?;
set_float_property(cx, &element_object, "x", *x)?;
set_float_property(cx, &element_object, "y", *y)?;
}
PathEvent::Line(PathEventLine { from_x, from_y, to_x, to_y }) => {
set_string_property(cx, &element_object, "type", "event_line")?;
set_float_property(cx, &element_object, "from_x", *from_x)?;
set_float_property(cx, &element_object, "from_y", *from_y)?;
set_float_property(cx, &element_object, "to_x", *to_x)?;
set_float_property(cx, &element_object, "to_y", *to_y)?;
}
PathEvent::Quadratic(PathEventQuadratic {
from_x,
from_y,
control_x,
control_y,
to_x,
to_y,
}) => {
set_string_property(cx, &element_object, "type", "event_quadratic")?;
set_float_property(cx, &element_object, "from_x", *from_x)?;
set_float_property(cx, &element_object, "from_y", *from_y)?;
set_float_property(cx, &element_object, "control_x", *control_x)?;
set_float_property(cx, &element_object, "control_y", *control_y)?;
set_float_property(cx, &element_object, "to_x", *to_x)?;
set_float_property(cx, &element_object, "to_y", *to_y)?;
}
PathEvent::Cubic(PathEventCubic {
from_x,
from_y,
control1_x,
control1_y,
control2_x,
control2_y,
to_x,
to_y,
}) => {
set_string_property(cx, &element_object, "type", "event_cubic")?;
set_float_property(cx, &element_object, "from_x", *from_x)?;
set_float_property(cx, &element_object, "from_y", *from_y)?;
set_float_property(cx, &element_object, "control1_x", *control1_x)?;
set_float_property(cx, &element_object, "control1_y", *control1_y)?;
set_float_property(cx, &element_object, "control2_x", *control2_x)?;
set_float_property(cx, &element_object, "control2_y", *control2_y)?;
set_float_property(cx, &element_object, "to_x", *to_x)?;
set_float_property(cx, &element_object, "to_y", *to_y)?;
}
PathEvent::End(PathEventEnd {
first_x,
first_y,
last_x,
last_y,
close,
}) => {
set_string_property(cx, &element_object, "type", "event_end")?;
set_float_property(cx, &element_object, "first_x", *first_x)?;
set_float_property(cx, &element_object, "first_y", *first_y)?;
set_float_property(cx, &element_object, "last_x", *last_x)?;
set_float_property(cx, &element_object, "last_y", *last_y)?;
set_bool_property(cx, &element_object, "close", *close)?;
}
}
js_array.set(cx, i as u32, element_object)?;
}
js_array.as_value(cx)
todo!()
}
}
})

View file

@ -931,23 +931,6 @@ fn compute_layout(component: &Rc<Component>) -> Vec<String> {
res
}
fn new_path_event(event_name: &str, fields: &[(&str, String)]) -> String {
let fields_initialization: Vec<String> = fields
.iter()
.map(|(prop, initializer)| format!("var.{} = {};", prop, initializer))
.collect();
format!(
r#"[&](){{
{} var{{}};
{}
return var;
}}()"#,
event_name,
fields_initialization.join("\n")
)
}
fn compile_path(path: &crate::expression_tree::Path, component: &Rc<Component>) -> String {
match path {
crate::expression_tree::Path::Elements(elements) => {
@ -980,89 +963,73 @@ fn compile_path(path: &crate::expression_tree::Path, component: &Rc<Component>)
)
}
crate::expression_tree::Path::Events(events) => {
let converted_elements: Vec<String> = compile_path_events(events);
let (converted_events, converted_coordinates) = compile_path_events(events);
format!(
r#"[&](){{
sixtyfps::PathEvent events[{}] = {{
{}
}};
return sixtyfps::PathElements(&events[0], std::size(events));
sixtyfps::Point coordinates[{}] = {{
{}
}};
return sixtyfps::PathElements(&events[0], std::size(events), &coordinates[0], std::size(coordinates));
}}()"#,
converted_elements.len(),
converted_elements.join(",")
converted_events.len(),
converted_events.join(","),
converted_coordinates.len(),
converted_coordinates.join(",")
)
}
}
}
fn compile_path_events(events: &crate::expression_tree::PathEvents) -> Vec<String> {
fn compile_path_events(events: &crate::expression_tree::PathEvents) -> (Vec<String>, Vec<String>) {
use lyon::path::Event;
events
let mut coordinates = Vec::new();
let events = events
.iter()
.map(|event| match event {
Event::Begin { at } => format!(
"sixtyfps::PathEvent::Begin({})",
new_path_event(
"sixtyfps::PathEventBegin",
&[("x", at.x.to_string()), ("y", at.y.to_string())]
)
),
Event::Line { from, to } => format!(
"sixtyfps::PathEvent::Line({})",
new_path_event(
"sixtyfps::PathEventLine",
&[
("from_x", from.x.to_string()),
("from_y", from.y.to_string()),
("to_x", to.x.to_string()),
("to_y", to.y.to_string())
]
)
),
Event::Quadratic { from, ctrl, to } => format!(
"sixtyfps::PathEvent::Quadratic({})",
new_path_event(
"sixtyfps::PathEventQuadratic",
&[
("from_x", from.x.to_string()),
("from_y", from.y.to_string()),
("control_x", ctrl.x.to_string()),
("control_y", ctrl.y.to_string()),
("to_x", to.x.to_string()),
("to_y", to.y.to_string())
]
)
),
Event::Cubic { from, ctrl1, ctrl2, to } => format!(
"sixtyfps::PathEvent::Cubic({})",
new_path_event(
"sixtyfps::PathEventCubic",
&[
("from_x", from.x.to_string()),
("from_y", from.y.to_string()),
("control1_x", ctrl1.x.to_string()),
("control1_y", ctrl1.y.to_string()),
("control2_x", ctrl2.x.to_string()),
("control2_y", ctrl2.y.to_string()),
("to_x", to.x.to_string()),
("to_y", to.y.to_string())
]
)
),
Event::End { last, first, close } => format!(
"sixtyfps::PathEvent::End({})",
new_path_event(
"sixtyfps::PathEventEnd",
&[
("first_x", first.x.to_string()),
("first_y", first.y.to_string()),
("last_x", last.x.to_string()),
("last_y", last.y.to_string()),
("close", close.to_string())
]
)
),
})
.collect()
Event::Begin { at } => {
coordinates.push(at);
"sixtyfps::PathEvent::Begin"
}
Event::Line { from, to } => {
coordinates.push(from);
coordinates.push(to);
"sixtyfps::PathEvent::Line"
}
Event::Quadratic { from, ctrl, to } => {
coordinates.push(from);
coordinates.push(ctrl);
coordinates.push(to);
"sixtyfps::PathEvent::Quadratic"
}
Event::Cubic { from, ctrl1, ctrl2, to } => {
coordinates.push(from);
coordinates.push(ctrl1);
coordinates.push(ctrl2);
coordinates.push(to);
"sixtyfps::PathEvent::Cubic"
}
Event::End { last, first, close } => {
debug_assert_eq!(coordinates.first(), Some(&first));
debug_assert_eq!(coordinates.last(), Some(&last));
if *close {
"sixtyfps::PathEvent::EndClosed"
} else {
"sixtyfps::PathEvent::EndOpen"
}
}
})
.map(String::from)
.collect();
let coordinates = coordinates
.into_iter()
.map(|pt| format!("sixtyfps::Point{{{}, {}}}", pt.x, pt.y))
.collect();
(events, coordinates)
}

View file

@ -791,52 +791,56 @@ fn compute_layout(component: &Rc<Component>) -> TokenStream {
fn compile_path_events(events: &crate::expression_tree::PathEvents) -> TokenStream {
use lyon::path::Event;
let mut coordinates = Vec::new();
let converted_events: Vec<proc_macro2::TokenStream> = events
.iter()
.map(|event| match event {
Event::Begin { at } => {
let x = at.x;
let y = at.y;
quote!(sixtyfps::re_exports::PathEvent::Begin(sixtyfps::re_exports::PathEventBegin{x: #x, y: #y}))
coordinates.push(at);
quote!(sixtyfps::re_exports::PathEvent::Begin)
}
Event::Line { from, to } => {
let from_x = from.x;
let from_y = from.y;
let to_x = to.x;
let to_y = to.y;
quote!(sixtyfps::re_exports::PathEvent::Line(sixtyfps::re_exports::PathEventLine{from_x: #from_x, from_y: #from_y, to_x: #to_x, to_y: #to_y}))
coordinates.push(from);
coordinates.push(to);
quote!(sixtyfps::re_exports::PathEvent::Line)
}
Event::Quadratic { from, ctrl, to } => {
let from_x = from.x;
let from_y = from.y;
let control_x = ctrl.x;
let control_y = ctrl.y;
let to_x = to.x;
let to_y = to.y;
quote!(sixtyfps::re_exports::PathEvent::Quadratic(sixtyfps::re_exports::PathEventQuadratic{from_x: #from_x, from_y: #from_y, control_x: #control_x, control_y: #control_y, to_x: #to_x, to_y: #to_y}))
coordinates.push(from);
coordinates.push(ctrl);
coordinates.push(to);
quote!(sixtyfps::re_exports::PathEvent::Quadratic)
}
Event::Cubic { from, ctrl1, ctrl2, to } => {
let from_x = from.x;
let from_y = from.y;
let control1_x = ctrl1.x;
let control1_y = ctrl1.y;
let control2_x = ctrl2.x;
let control2_y = ctrl2.y;
let to_x = to.x;
let to_y = to.y;
quote!(sixtyfps::re_exports::PathEvent::Cubic(sixtyfps::re_exports::PathEventCubic{from_x: #from_x, from_y: #from_y, control1_x: #control1_x, control1_y: #control1_y, control2_x: #control2_x, control2_y: #control2_y, to_x: #to_x, to_y: #to_y}))
coordinates.push(from);
coordinates.push(ctrl1);
coordinates.push(ctrl2);
coordinates.push(to);
quote!(sixtyfps::re_exports::PathEvent::Cubic)
}
Event::End { last, first, close } => {
let first_x = first.x;
let first_y = first.y;
let last_x = last.x;
let last_y = last.y;
quote!(sixtyfps::re_exports::PathEvent::End(sixtyfps::re_exports::PathEventEnd{first_x: #first_x, first_y: #first_y, last_x: #last_x, last_y: #last_y, close: #close}))
debug_assert_eq!(coordinates.first(), Some(&first));
debug_assert_eq!(coordinates.last(), Some(&last));
if *close {
quote!(sixtyfps::re_exports::PathEvent::EndClosed)
} else {
quote!(sixtyfps::re_exports::PathEvent::EndOpen)
}
}
})
.collect();
quote!(sixtyfps::re_exports::SharedArray::<sixtyfps::re_exports::PathEvent>::from(&[#(#converted_events),*]))
let coordinates: Vec<TokenStream> = coordinates
.into_iter()
.map(|pt| {
let x = pt.x;
let y = pt.y;
quote!(sixtyfps::re_exports::Point::new(#x, #y))
})
.collect();
quote!(sixtyfps::re_exports::SharedArray::<sixtyfps::re_exports::PathEvent>::from(&[#(#converted_events),*]),
sixtyfps::re_exports::SharedArray::<sixtyfps::re_exports::Point>::from(&[#(#coordinates),*]))
}
fn compile_path(path: &Path, component: &Rc<Component>) -> TokenStream {

View file

@ -426,86 +426,67 @@ pub struct PathEventEnd {
/// generated at compile time from a higher-level description, such as SVG commands.
pub enum PathEvent {
/// The beginning of the path.
Begin(PathEventBegin),
Begin,
/// A straight line on the path.
Line(PathEventLine),
Line,
/// A quadratic bezier curve on the path.
Quadratic(PathEventQuadratic),
Quadratic,
/// A cubic bezier curve on the path.
Cubic(PathEventCubic),
/// The end of the path.
End(PathEventEnd),
Cubic,
/// The end of the path that remains open.
EndOpen,
/// The end of a path that is closed.
EndClosed,
}
impl From<&PathEvent> for lyon::path::Event<lyon::math::Point, lyon::math::Point> {
fn from(event: &PathEvent) -> Self {
use lyon::math::Point;
use lyon::path::Event;
match event {
PathEvent::Begin(begin) => Event::Begin { at: Point::new(begin.x, begin.y) },
PathEvent::Line(line) => Event::Line {
from: Point::new(line.from_x, line.from_y),
to: Point::new(line.to_x, line.to_y),
},
PathEvent::Quadratic(curve) => Event::Quadratic {
from: Point::new(curve.from_x, curve.from_y),
ctrl: Point::new(curve.control_x, curve.control_y),
to: Point::new(curve.to_x, curve.to_y),
},
PathEvent::Cubic(curve) => Event::Cubic {
from: Point::new(curve.from_x, curve.from_y),
ctrl1: Point::new(curve.control1_x, curve.control1_y),
ctrl2: Point::new(curve.control2_x, curve.control2_y),
to: Point::new(curve.to_x, curve.to_y),
},
PathEvent::End(end) => Event::End {
first: Point::new(end.first_x, end.first_y),
last: Point::new(end.last_x, end.last_y),
close: end.close,
},
struct ToLyonPathEventIterator<'a> {
events_it: std::slice::Iter<'a, PathEvent>,
coordinates_it: std::slice::Iter<'a, Point>,
first: Option<&'a Point>,
last: Option<&'a Point>,
}
impl<'a> Iterator for ToLyonPathEventIterator<'a> {
type Item = lyon::path::Event<lyon::math::Point, lyon::math::Point>;
fn next(&mut self) -> Option<Self::Item> {
use lyon::path::Event;
self.events_it.next().map(|event| match event {
PathEvent::Begin => Event::Begin { at: self.coordinates_it.next().unwrap().clone() },
PathEvent::Line => Event::Line {
from: self.coordinates_it.next().unwrap().clone(),
to: self.coordinates_it.next().unwrap().clone(),
},
PathEvent::Quadratic => Event::Quadratic {
from: self.coordinates_it.next().unwrap().clone(),
ctrl: self.coordinates_it.next().unwrap().clone(),
to: self.coordinates_it.next().unwrap().clone(),
},
PathEvent::Cubic => Event::Cubic {
from: self.coordinates_it.next().unwrap().clone(),
ctrl1: self.coordinates_it.next().unwrap().clone(),
ctrl2: self.coordinates_it.next().unwrap().clone(),
to: self.coordinates_it.next().unwrap().clone(),
},
PathEvent::EndOpen => Event::End {
first: self.first.unwrap().clone(),
last: self.last.unwrap().clone(),
close: false,
},
PathEvent::EndClosed => Event::End {
first: self.first.unwrap().clone(),
last: self.last.unwrap().clone(),
close: true,
},
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.events_it.size_hint()
}
}
impl From<&lyon::path::Event<lyon::math::Point, lyon::math::Point>> for PathEvent {
fn from(event: &lyon::path::Event<lyon::math::Point, lyon::math::Point>) -> Self {
use lyon::path::Event;
match event {
Event::Begin { at } => PathEvent::Begin(PathEventBegin { x: at.x, y: at.y }),
Event::Line { from, to } => PathEvent::Line(PathEventLine {
from_x: from.x,
from_y: from.y,
to_x: to.x,
to_y: to.y,
}),
Event::Quadratic { from, ctrl, to } => PathEvent::Quadratic(PathEventQuadratic {
from_x: from.x,
from_y: from.y,
control_x: ctrl.x,
control_y: ctrl.y,
to_x: to.x,
to_y: to.y,
}),
Event::Cubic { from, ctrl1, ctrl2, to } => PathEvent::Cubic(PathEventCubic {
from_x: from.x,
from_y: from.y,
control1_x: ctrl1.x,
control1_y: ctrl1.y,
control2_x: ctrl2.x,
control2_y: ctrl2.y,
to_x: to.x,
to_y: to.y,
}),
Event::End { last, first, close } => PathEvent::End(PathEventEnd {
first_x: first.x,
first_y: first.y,
last_x: last.x,
last_y: last.y,
close: *close,
}),
}
}
}
impl<'a> ExactSizeIterator for ToLyonPathEventIterator<'a> {}
#[repr(C)]
#[derive(Clone, Debug, PartialEq)]
@ -518,7 +499,7 @@ pub enum PathElements {
/// SharedElements is used to make PathElements from shared arrays of elements.
SharedElements(crate::SharedArray<PathElement>),
/// PathEvents describe the elements of the path as a series of low-level events.
PathEvents(crate::SharedArray<PathEvent>),
PathEvents(crate::SharedArray<PathEvent>, crate::SharedArray<Point>),
}
impl Default for PathElements {
@ -540,9 +521,14 @@ impl PathElements {
}
/// Returns an iterator over all events if the elements are represented as low-level events.
pub fn events_iter(&self) -> Option<std::slice::Iter<PathEvent>> {
match self {
PathElements::PathEvents(events) => Some(events.as_slice().iter()),
fn events_iter(&self) -> Option<ToLyonPathEventIterator> {
match &self {
PathElements::PathEvents(events, coordinates) => Some(ToLyonPathEventIterator {
events_it: events.iter(),
coordinates_it: coordinates.iter(),
first: coordinates.first(),
last: coordinates.last(),
}),
_ => None,
}
}
@ -615,12 +601,18 @@ pub unsafe extern "C" fn sixtyfps_new_path_elements(
#[no_mangle]
/// This function is used for the low-level C++ interface to allocate the backing vector for a shared path event array.
pub unsafe extern "C" fn sixtyfps_new_path_events(
out: *mut c_void,
out_events: *mut c_void,
out_coordinates: *mut c_void,
first_event: *const PathEvent,
count: usize,
event_count: usize,
first_coordinate: *const Point,
coordinate_count: usize,
) {
let arr = crate::SharedArray::from(std::slice::from_raw_parts(first_event, count));
core::ptr::write(out as *mut crate::SharedArray<PathEvent>, arr.clone());
let events = crate::SharedArray::from(std::slice::from_raw_parts(first_event, event_count));
core::ptr::write(out_events as *mut crate::SharedArray<PathEvent>, events.clone());
let coordinates =
crate::SharedArray::from(std::slice::from_raw_parts(first_coordinate, coordinate_count));
core::ptr::write(out_coordinates as *mut crate::SharedArray<Point>, coordinates.clone());
}
/// Each item return a RenderingPrimitive to the backend with information about what to draw.

View file

@ -11,4 +11,5 @@ path = "lib.rs"
sixtyfps_corelib = { path = "../corelib", features = ["rtti"] }
vtable = { path="../../helper_crates/vtable" }
sixtyfps_compilerlib = { path = "../../sixtyfps_compiler", features = ["display-diagnostics"] }
lyon = { version = "0.15.8" }

View file

@ -6,8 +6,9 @@ use sixtyfps_compilerlib::expression_tree::{
use sixtyfps_compilerlib::{object_tree::ElementRc, typeregister::Type};
use sixtyfps_corelib as corelib;
use sixtyfps_corelib::{
abi::datastructures::ItemRef, abi::primitives::PropertyAnimation, Color, EvaluationContext,
PathElements, Resource, SharedString,
abi::datastructures::ItemRef, abi::datastructures::PathElement,
abi::primitives::PropertyAnimation, Color, EvaluationContext, PathElements, Resource,
SharedArray, SharedString,
};
use std::{collections::HashMap, rc::Rc};
@ -363,26 +364,71 @@ pub fn new_struct_with_bindings<
element
}
fn convert_from_lyon_path<'a>(
it: impl IntoIterator<Item = &'a lyon::path::Event<lyon::math::Point, lyon::math::Point>>,
) -> PathElements {
use lyon::path::Event;
use sixtyfps_corelib::abi::datastructures::PathEvent;
let mut coordinates = Vec::new();
let events = it
.into_iter()
.map(|event| match event {
Event::Begin { at } => {
coordinates.push(at);
PathEvent::Begin
}
Event::Line { from, to } => {
coordinates.push(from);
coordinates.push(to);
PathEvent::Line
}
Event::Quadratic { from, ctrl, to } => {
coordinates.push(from);
coordinates.push(ctrl);
coordinates.push(to);
PathEvent::Quadratic
}
Event::Cubic { from, ctrl1, ctrl2, to } => {
coordinates.push(from);
coordinates.push(ctrl1);
coordinates.push(ctrl2);
coordinates.push(to);
PathEvent::Cubic
}
Event::End { last, first, close } => {
debug_assert_eq!(coordinates.first(), Some(&first));
debug_assert_eq!(coordinates.last(), Some(&last));
if *close {
PathEvent::EndClosed
} else {
PathEvent::EndOpen
}
}
})
.collect::<Vec<_>>();
PathElements::PathEvents(
SharedArray::from(&events),
SharedArray::from_iter(coordinates.into_iter().cloned()),
)
}
pub fn convert_path(
path: &ExprPath,
component_type: &crate::ComponentDescription,
eval_context: &corelib::EvaluationContext,
) -> sixtyfps_corelib::abi::datastructures::PathElements {
) -> PathElements {
match path {
ExprPath::Elements(elements) => {
PathElements::SharedElements(sixtyfps_corelib::SharedArray::<
sixtyfps_corelib::abi::datastructures::PathElement,
>::from_iter(
PathElements::SharedElements(SharedArray::<PathElement>::from_iter(
elements
.iter()
.map(|element| convert_path_element(element, component_type, eval_context)),
))
}
ExprPath::Events(events) => PathElements::PathEvents(sixtyfps_corelib::SharedArray::<
sixtyfps_corelib::abi::datastructures::PathEvent,
>::from_iter(
events.iter().map(|event| event.into()),
)),
ExprPath::Events(events) => convert_from_lyon_path(events.iter()),
}
}
@ -390,15 +436,19 @@ fn convert_path_element(
expr_element: &ExprPathElement,
component_type: &crate::ComponentDescription,
eval_context: &corelib::EvaluationContext,
) -> sixtyfps_corelib::abi::datastructures::PathElement {
) -> PathElement {
match expr_element.element_type.class_name.as_str() {
"LineTo" => sixtyfps_corelib::abi::datastructures::PathElement::LineTo(
new_struct_with_bindings(&expr_element.bindings, component_type, eval_context),
),
"ArcTo" => sixtyfps_corelib::abi::datastructures::PathElement::ArcTo(
new_struct_with_bindings(&expr_element.bindings, component_type, eval_context),
),
"Close" => sixtyfps_corelib::abi::datastructures::PathElement::Close,
"LineTo" => PathElement::LineTo(new_struct_with_bindings(
&expr_element.bindings,
component_type,
eval_context,
)),
"ArcTo" => PathElement::ArcTo(new_struct_with_bindings(
&expr_element.bindings,
component_type,
eval_context,
)),
"Close" => PathElement::Close,
_ => panic!(
"Cannot create unsupported path element {}",
expr_element.element_type.class_name