Fix number to string conversion in C++

This commit is contained in:
Olivier Goffart 2020-05-27 16:17:12 +02:00
parent 486b2ab8f8
commit 5580b5112f
5 changed files with 90 additions and 59 deletions

View file

@ -31,7 +31,11 @@ struct SharedString
operator std::string_view() const { return internal::sixtyfps_shared_string_bytes(this); }
auto data() const -> const char * { return internal::sixtyfps_shared_string_bytes(this); }
static SharedString from_number(double n) { return SharedString(n); }
private:
/// Use SharedString::from_number
explicit SharedString(double n) { internal::sixtyfps_shared_string_from_number(this, n); }
void *inner; // opaque
};
}

View file

@ -79,7 +79,7 @@ Hello := Rectangle {
button_text: "+";
}
property<int32> counter;
counter_label := Text { x: 100; y: 300; text: "0"; color: black; }
counter_label := Text { x: 100; y: 300; text: counter; color: black; }
ButtonRectangle {
color: 4289374890;
x: 50;

View file

@ -11,17 +11,11 @@ int main() {
component.plus_clicked.set_handler([](auto...){
auto &counter = component.counter;
counter.set(counter.get() + 1);
// FIXME: this _13 is an internal detail and should be private anyway. We muse use some
// alias or way to expose the property (same for the _ before signals)
component.counter_label_11.text.set(std::string_view(std::to_string(counter.get())));
std::cout << "PLUS: " << std::string_view(component.counter_label_11.text.get()) << std::endl;
});
component.minus_clicked.set_handler([](auto...){
auto &counter = component.counter;
counter.set(counter.get() - 1);
component.counter_label_11.text.set(std::string_view(std::to_string(counter.get())));
std::cout << "MINUS: " << std::string_view(component.counter_label_11.text.get()) << std::endl;
});
sixtyfps::run(&component);

View file

@ -162,7 +162,7 @@ fn handle_item(
let id = &item.id;
init.extend(item.bindings.iter().map(|(s, i)| {
use crate::expression_tree::{Expression, Expression::*};
use crate::expression_tree::Expression;
match i {
Expression::SignalReference { component:_, element:_, name } => {
let signal_accessor_prefix = if item.signals_declaration.contains(s) {
@ -183,14 +183,7 @@ fn handle_item(
format!("{id}.", id = id.clone())
};
let init = match &i {
StringLiteral(s) => {
format!(r#"sixtyfps::SharedString("{}")"#, s.escape_default())
}
NumberLiteral(n) => n.to_string(),
PropertyReference { name, .. } => format!(r#"{}.get()"#, name),
_ => format!("\n#error: unsupported expression {:?}\n", i),
};
let init = compile_expression(i);
format!(
"{accessor_prefix}{cpp_prop}.set({init});",
accessor_prefix = accessor_prefix,
@ -298,18 +291,28 @@ pub fn generate(component: &Component, diag: &mut Diagnostics) -> Option<impl st
init: Some("{ nullptr, sixtyfps::dummy_destory, tree_fn }".to_owned()),
}));
/*x.declarations.push(Declaration::Function(Function {
name: "main".into(),
signature: "() -> int".to_owned(),
statements: Some(vec![
format!("static {} component;", component.id),
format!("sixtyfps::run(&component);"),
]),
..Default::default()
}));*/
if diag.has_error() {
None
} else {
Some(x)
}
}
fn compile_expression(e: &crate::expression_tree::Expression) -> String {
use crate::expression_tree::Expression::*;
match e {
StringLiteral(s) => format!(r#"sixtyfps::SharedString("{}")"#, s.escape_default()),
NumberLiteral(n) => n.to_string(),
PropertyReference { name, .. } => format!(r#"{}.get()"#, name),
Cast { from, to } => {
let f = compile_expression(&*from);
match (from.ty(), to) {
(Type::Float32, Type::String) | (Type::Int32, Type::String) => {
format!("sixtyfps::SharedString::from_number({})", f)
}
_ => f,
}
}
_ => format!("\n#error: unsupported expression {:?}\n", e),
}
}

View file

@ -228,40 +228,6 @@ where
impl Eq for SharedString {}
/// for cbingen.
#[allow(non_camel_case_types)]
type c_char = u8;
#[no_mangle]
pub extern "C" fn sixtyfps_shared_string_bytes(ss: &SharedString) -> *const c_char {
ss.as_ptr()
}
#[no_mangle]
/// Destroy the shared string
pub unsafe extern "C" fn sixtyfps_shared_string_drop(ss: *const SharedString) {
core::ptr::read(ss);
}
#[no_mangle]
/// Increment the reference count of the string.
/// the resulting structure must be passed to sixtyfps_shared_string_drop
pub unsafe extern "C" fn sixtyfps_shared_string_clone(out: *mut SharedString, ss: &SharedString) {
core::ptr::write(out, ss.clone())
}
#[no_mangle]
/// Safety: bytes must be a valid utf-8 string of size len wihout null inside.
/// the resulting structure must be passed to sixtyfps_shared_string_drop
pub unsafe extern "C" fn sixtyfps_shared_string_from_bytes(
out: *mut SharedString,
bytes: *const c_char,
len: usize,
) {
let str = core::str::from_utf8_unchecked(core::slice::from_raw_parts(bytes, len));
core::ptr::write(out, SharedString::from(str));
}
#[test]
fn simple_test() {
let x = SharedString::from("hello world!");
@ -279,3 +245,67 @@ fn simple_test() {
&*std::ffi::CString::new("hello world!").unwrap()
);
}
/// for cbingen.
#[allow(non_camel_case_types)]
type c_char = u8;
#[no_mangle]
pub extern "C" fn sixtyfps_shared_string_bytes(ss: &SharedString) -> *const c_char {
ss.as_ptr()
}
#[no_mangle]
/// Destroy the shared string
pub unsafe extern "C" fn sixtyfps_shared_string_drop(ss: *const SharedString) {
core::ptr::read(ss);
}
#[no_mangle]
/// Increment the reference count of the string.
/// The resulting structure must be passed to sixtyfps_shared_string_drop
pub unsafe extern "C" fn sixtyfps_shared_string_clone(out: *mut SharedString, ss: &SharedString) {
core::ptr::write(out, ss.clone())
}
#[no_mangle]
/// Safety: bytes must be a valid utf-8 string of size len wihout null inside.
/// The resulting structure must be passed to sixtyfps_shared_string_drop
pub unsafe extern "C" fn sixtyfps_shared_string_from_bytes(
out: *mut SharedString,
bytes: *const c_char,
len: usize,
) {
let str = core::str::from_utf8_unchecked(core::slice::from_raw_parts(bytes, len));
core::ptr::write(out, SharedString::from(str));
}
/// Create a string from a number.
/// The resulting structure must be passed to sixtyfps_shared_string_drop
#[no_mangle]
pub unsafe extern "C" fn sixtyfps_shared_string_from_number(out: *mut SharedString, n: f64) {
// TODO: implement Write for SharedString so this can be done without alocation
let str = format!("{}", n);
core::ptr::write(out, SharedString::from(str.as_str()));
}
#[test]
fn test_sixtyfps_shared_string_from_number() {
unsafe {
let mut s = core::mem::MaybeUninit::uninit();
sixtyfps_shared_string_from_number(s.as_mut_ptr(), 45.);
assert_eq!(s.assume_init(), "45");
let mut s = core::mem::MaybeUninit::uninit();
sixtyfps_shared_string_from_number(s.as_mut_ptr(), 45.12);
assert_eq!(s.assume_init(), "45.12");
let mut s = core::mem::MaybeUninit::uninit();
sixtyfps_shared_string_from_number(s.as_mut_ptr(), -1325466.);
assert_eq!(s.assume_init(), "-1325466");
let mut s = core::mem::MaybeUninit::uninit();
sixtyfps_shared_string_from_number(s.as_mut_ptr(), -0.);
assert_eq!(s.assume_init(), "0");
}
}