diff --git a/Cargo.toml b/Cargo.toml index 9ae2cbd32..7235bd524 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ 'sixtyfps_compiler/parser_test_macro', 'api/sixtyfps-rs', 'api/sixtyfps-rs/sixtyfps-rs-macro', + 'tools/viewer', 'examples/graphicstest', 'examples/rusttest', 'helper_crates/const-field-offset', diff --git a/helper_crates/const-field-offset/src/lib.rs b/helper_crates/const-field-offset/src/lib.rs index 125c3a927..cd4bf00ed 100644 --- a/helper_crates/const-field-offset/src/lib.rs +++ b/helper_crates/const-field-offset/src/lib.rs @@ -66,12 +66,12 @@ pub fn const_field_offset(input: TokenStream) -> TokenStream { // Build the output, possibly using quasi-quotation let expanded = quote! { - struct #field_struct_name { - #(#fields : usize,)* + pub struct #field_struct_name { + #(pub #fields : usize,)* } impl #struct_name { - /*pub ??? */ const fn field_offsets() -> #field_struct_name { + pub const fn field_offsets() -> #field_struct_name { let mut len = 0usize; #field_struct_name { #( #fields : { diff --git a/tools/viewer/Cargo.toml b/tools/viewer/Cargo.toml new file mode 100644 index 000000000..4929e1138 --- /dev/null +++ b/tools/viewer/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "viewer" +version = "0.1.0" +authors = ["Olivier Goffart "] +edition = "2018" + + +[dependencies] +corelib = { path="../../sixtyfps_runtime/corelib" } +sixtyfps_compiler = { path = "../../sixtyfps_compiler", features = ["display-diagnostics"] } +# FIXME: make optional and configurable backends +gl = { path = "../../sixtyfps_runtime/rendering_backends/gl" } +structopt = "0.3.14" +codemap-diagnostic = "0.1.1" +codemap = "0.1" + + +[[bin]] +name = "viewer" +path = "main.rs" diff --git a/tools/viewer/main.rs b/tools/viewer/main.rs new file mode 100644 index 000000000..eb99ae7ca --- /dev/null +++ b/tools/viewer/main.rs @@ -0,0 +1,175 @@ +use corelib::abi::datastructures::{ComponentImpl, ComponentType}; +use sixtyfps_compiler::object_tree::Expression; +use std::collections::HashMap; +use structopt::StructOpt; + +#[derive(StructOpt)] +struct Cli { + #[structopt(name = "path to .60 file", parse(from_os_str))] + path: std::path::PathBuf, +} + +trait PropertyWriter { + unsafe fn write(ptr: *mut u8, value: &Expression); +} + +impl PropertyWriter for f32 { + unsafe fn write(ptr: *mut u8, value: &Expression) { + let val: Self = match value { + Expression::NumberLiteral(v) => *v as _, + _ => todo!(), + }; + std::ptr::write(ptr as *mut Self, val); + } +} + +impl PropertyWriter for u32 { + unsafe fn write(ptr: *mut u8, value: &Expression) { + let val: Self = match value { + Expression::NumberLiteral(v) => *v as _, + _ => todo!(), + }; + std::ptr::write(ptr as *mut Self, val); + } +} + +impl PropertyWriter for *const i8 { + unsafe fn write(ptr: *mut u8, value: &Expression) { + let val: Self = match value { + Expression::StringLiteral(v) => { + // FIXME that's a leak + std::ffi::CString::new(v.as_str()).unwrap().into_raw() as _ + } + _ => todo!(), + }; + std::ptr::write(ptr as *mut Self, val); + } +} + +unsafe fn construct(ptr: *mut corelib::abi::datastructures::ItemImpl) { + core::ptr::write(ptr as *mut T, T::default()); +} + +unsafe fn set_property(ptr: *mut u8, e: &Expression) { + T::write(ptr, e); +} + +unsafe extern "C" fn dummy_destroy(_: *const ComponentType, _: *mut ComponentImpl) { + panic!(); +} + +#[repr(C)] +struct MyComponentType { + ct: ComponentType, + it: Vec, +} + +unsafe extern "C" fn item_tree( + c: *const ComponentType, +) -> *const corelib::abi::datastructures::ItemTreeNode { + (*(c as *const MyComponentType)).it.as_ptr() +} + +struct RuntimeTypeInfo { + vtable: *const corelib::abi::datastructures::ItemVTable, + construct: unsafe fn(*mut corelib::abi::datastructures::ItemImpl), + properties: HashMap<&'static str, (usize, unsafe fn(*mut u8, &Expression))>, + size: usize, +} + +fn main() -> std::io::Result<()> { + use sixtyfps_compiler::*; + let args = Cli::from_args(); + let source = std::fs::read_to_string(&args.path)?; + let (syntax_node, mut diag) = parser::parse(&source); + let tr = typeregister::TypeRegister::builtin(); + let tree = object_tree::Document::from_node(syntax_node, &mut diag, &tr); + if !diag.inner.is_empty() { + diag.print(args.path.to_string_lossy().into_owned(), source); + std::process::exit(-1); + } + + use corelib::abi::primitives::{Image, Rectangle}; + + // FIXME: thus obviously is unsafe and not great + let mut rtti = HashMap::new(); + rtti.insert( + "Rectangle", + RuntimeTypeInfo { + vtable: &corelib::abi::primitives::RectangleVTable as _, + construct: construct::, + properties: [ + ("x", (Rectangle::field_offsets().x, set_property:: as _)), + ("y", (Rectangle::field_offsets().y, set_property:: as _)), + ("width", (Rectangle::field_offsets().width, set_property:: as _)), + ("height", (Rectangle::field_offsets().height, set_property:: as _)), + ("color", (Rectangle::field_offsets().color, set_property:: as _)), + ] + .iter() + .cloned() + .collect(), + size: std::mem::size_of::(), + }, + ); + rtti.insert( + "Image", + RuntimeTypeInfo { + vtable: &corelib::abi::primitives::ImageVTable as _, + construct: construct::, + properties: [ + ("x", (Image::field_offsets().x, set_property:: as _)), + ("y", (Image::field_offsets().y, set_property:: as _)), + ("width", (Image::field_offsets().width, set_property:: as _)), + ("height", (Image::field_offsets().height, set_property:: as _)), + ("source", (Image::field_offsets().source, set_property::<*const i8> as _)), + ] + .iter() + .cloned() + .collect(), + size: std::mem::size_of::(), + }, + ); + + let l = lower::LoweredComponent::lower(&*tree.root_component); + + let mut tree_array = vec![]; + let mut current_offset = 0usize; + let mut items_types = vec![]; + + generator::build_array_helper(&l, |item, child_offset| { + let rt = &rtti[&*item.native_type.class_name]; + tree_array.push(corelib::abi::datastructures::ItemTreeNode::Item { + offset: current_offset as isize, + vtable: rt.vtable, + children_index: child_offset, + chilren_count: item.children.len() as _, + }); + items_types.push((current_offset, rt, item.init_properties.clone())); + current_offset += rt.size; + }); + + let t = ComponentType { create: None, destroy: dummy_destroy, item_tree }; + let t = MyComponentType { ct: t, it: tree_array }; + + let mut my_impl = Vec::::new(); + my_impl.resize(current_offset / 8 + 1, 0); + let mem = my_impl.as_mut_ptr() as *mut u8; + + for (offset, rtti, properties) in items_types { + unsafe { + let item = mem.offset(offset as isize); + (rtti.construct)(item as _); + for (prop, expr) in properties { + let (o, set) = rtti.properties[&*prop]; + set(item.offset(o as isize), &expr); + } + } + } + + gl::sixtyfps_runtime_run_component_with_gl_renderer( + &t as *const MyComponentType as *const ComponentType, + std::ptr::NonNull::new(mem).unwrap().cast(), + ); + + Ok(()) +}