1504 lines
42 KiB
Rust
1504 lines
42 KiB
Rust
use configuration::*;
|
|
use configuration_private::*;
|
|
use std::io::{Result, Write};
|
|
use util::{snake_case, write_if_different};
|
|
|
|
fn rust_type(p: &Property) -> String {
|
|
if p.optional {
|
|
return format!("Option<{}>", p.property_type.rust_type());
|
|
}
|
|
p.property_type.rust_type().to_string()
|
|
}
|
|
|
|
fn rust_type_(p: &ItemProperty) -> String {
|
|
if p.optional {
|
|
return format!("Option<{}>", p.item_property_type.rust_type());
|
|
}
|
|
p.item_property_type.rust_type().to_string()
|
|
}
|
|
|
|
fn rust_return_type(p: &Property) -> String {
|
|
let mut type_: String = p.property_type.rust_type().to_string();
|
|
if type_ == "String" {
|
|
type_ = "str".to_string();
|
|
}
|
|
if type_ == "Vec<u8>" {
|
|
type_ = "[u8]".to_string();
|
|
}
|
|
if p.property_type.is_complex() {
|
|
type_ = "&".to_string() + &type_;
|
|
}
|
|
if p.optional {
|
|
return "Option<".to_string() + &type_ + ">";
|
|
}
|
|
type_
|
|
}
|
|
|
|
fn rust_return_type_(p: &ItemProperty) -> String {
|
|
let mut type_: String = p.item_property_type.rust_type().to_string();
|
|
if type_ == "String" && !p.rust_by_value {
|
|
type_ = "str".to_string();
|
|
}
|
|
if type_ == "Vec<u8>" && !p.rust_by_value {
|
|
type_ = "[u8]".to_string();
|
|
}
|
|
if p.item_property_type.is_complex() && !p.rust_by_value {
|
|
type_ = "&".to_string() + &type_;
|
|
}
|
|
if p.optional {
|
|
return "Option<".to_string() + &type_ + ">";
|
|
}
|
|
type_
|
|
}
|
|
|
|
fn rust_c_type(p: &ItemProperty) -> String {
|
|
if p.optional {
|
|
return format!("COption<{}>", p.item_property_type.rust_type());
|
|
}
|
|
p.item_property_type.rust_type().to_string()
|
|
}
|
|
|
|
fn rust_type_init(p: &Property) -> &str {
|
|
if p.optional {
|
|
return "None";
|
|
}
|
|
p.property_type.rust_type_init()
|
|
}
|
|
|
|
fn r_constructor_args_decl(r: &mut Vec<u8>, name: &str, o: &Object, conf: &Config) -> Result<()> {
|
|
write!(r, " {}: *mut {}QObject", snake_case(name), o.name)?;
|
|
for (p_name, p) in &o.properties {
|
|
if let Type::Object(object) = &p.property_type {
|
|
writeln!(r, ",")?;
|
|
r_constructor_args_decl(r, p_name, object, conf)?;
|
|
} else {
|
|
write!(
|
|
r,
|
|
",\n {}_{}_changed: fn(*const {}QObject)",
|
|
snake_case(name),
|
|
snake_case(p_name),
|
|
o.name
|
|
)?;
|
|
}
|
|
}
|
|
if o.object_type == ObjectType::List {
|
|
write!(
|
|
r,
|
|
",\n {}_new_data_ready: fn(*const {}QObject)",
|
|
snake_case(name),
|
|
o.name
|
|
)?;
|
|
} else if o.object_type == ObjectType::Tree {
|
|
write!(
|
|
r,
|
|
",\n {}_new_data_ready: fn(*const {}QObject, index: COption<usize>)",
|
|
snake_case(name),
|
|
o.name
|
|
)?;
|
|
}
|
|
if o.object_type != ObjectType::Object {
|
|
let index_decl = if o.object_type == ObjectType::Tree {
|
|
" index: COption<usize>,"
|
|
} else {
|
|
""
|
|
};
|
|
let dest_decl = if o.object_type == ObjectType::Tree {
|
|
" index: COption<usize>,"
|
|
} else {
|
|
""
|
|
};
|
|
write!(
|
|
r,
|
|
",
|
|
{2}_layout_about_to_be_changed: fn(*const {0}QObject),
|
|
{2}_layout_changed: fn(*const {0}QObject),
|
|
{2}_data_changed: fn(*const {0}QObject, usize, usize),
|
|
{2}_begin_reset_model: fn(*const {0}QObject),
|
|
{2}_end_reset_model: fn(*const {0}QObject),
|
|
{2}_begin_insert_rows: fn(*const {0}QObject,{1} usize, usize),
|
|
{2}_end_insert_rows: fn(*const {0}QObject),
|
|
{2}_begin_move_rows: fn(*const {0}QObject,{1} usize, usize,{3} usize),
|
|
{2}_end_move_rows: fn(*const {0}QObject),
|
|
{2}_begin_remove_rows: fn(*const {0}QObject,{1} usize, usize),
|
|
{2}_end_remove_rows: fn(*const {0}QObject)",
|
|
o.name,
|
|
index_decl,
|
|
snake_case(name),
|
|
dest_decl
|
|
)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn r_constructor_args(r: &mut Vec<u8>, name: &str, o: &Object, conf: &Config) -> Result<()> {
|
|
for (name, p) in &o.properties {
|
|
if let Type::Object(object) = &p.property_type {
|
|
r_constructor_args(r, name, object, conf)?;
|
|
}
|
|
}
|
|
writeln!(
|
|
r,
|
|
" let {}_emit = {}Emitter {{
|
|
qobject: Arc::new(Mutex::new({0})),",
|
|
snake_case(name),
|
|
o.name
|
|
)?;
|
|
for (p_name, p) in &o.properties {
|
|
if p.is_object() {
|
|
continue;
|
|
}
|
|
writeln!(
|
|
r,
|
|
" {}_changed: {}_{0}_changed,",
|
|
snake_case(p_name),
|
|
snake_case(name)
|
|
)?;
|
|
}
|
|
if o.object_type != ObjectType::Object {
|
|
writeln!(
|
|
r,
|
|
" new_data_ready: {}_new_data_ready,",
|
|
snake_case(name)
|
|
)?;
|
|
}
|
|
let mut model = String::new();
|
|
if o.object_type != ObjectType::Object {
|
|
let type_ = if o.object_type == ObjectType::List {
|
|
"List"
|
|
} else {
|
|
"Tree"
|
|
};
|
|
model.push_str(", model");
|
|
writeln!(
|
|
r,
|
|
" }};
|
|
let model = {}{} {{
|
|
qobject: {},
|
|
layout_about_to_be_changed: {2}_layout_about_to_be_changed,
|
|
layout_changed: {2}_layout_changed,
|
|
data_changed: {2}_data_changed,
|
|
begin_reset_model: {2}_begin_reset_model,
|
|
end_reset_model: {2}_end_reset_model,
|
|
begin_insert_rows: {2}_begin_insert_rows,
|
|
end_insert_rows: {2}_end_insert_rows,
|
|
begin_move_rows: {2}_begin_move_rows,
|
|
end_move_rows: {2}_end_move_rows,
|
|
begin_remove_rows: {2}_begin_remove_rows,
|
|
end_remove_rows: {2}_end_remove_rows,",
|
|
o.name,
|
|
type_,
|
|
snake_case(name)
|
|
)?;
|
|
}
|
|
write!(
|
|
r,
|
|
" }};\n let d_{} = {}::new({0}_emit{}",
|
|
snake_case(name),
|
|
o.name,
|
|
model
|
|
)?;
|
|
for (name, p) in &o.properties {
|
|
if p.is_object() {
|
|
write!(r, ",\n d_{}", snake_case(name))?;
|
|
}
|
|
}
|
|
writeln!(r, ");")
|
|
}
|
|
|
|
fn write_function(
|
|
r: &mut Vec<u8>,
|
|
(name, f): (&String, &Function),
|
|
lcname: &str,
|
|
o: &Object,
|
|
) -> Result<()> {
|
|
let lc = snake_case(name);
|
|
write!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {}_{}(ptr: *{} {}",
|
|
lcname,
|
|
lc,
|
|
if f.mutable { "mut" } else { "const" },
|
|
o.name
|
|
)?;
|
|
// write all the input arguments, for QString and QByteArray, write
|
|
// pointers to their content and the length which is int in Qt
|
|
for a in &f.arguments {
|
|
write!(r, ", ")?;
|
|
if a.argument_type.name() == "QString" {
|
|
write!(r, "{}_str: *const c_ushort, {0}_len: c_int", a.name)?;
|
|
} else if a.argument_type.name() == "QByteArray" {
|
|
write!(r, "{}_str: *const c_char, {0}_len: c_int", a.name)?;
|
|
} else {
|
|
write!(r, "{}: {}", a.name, a.argument_type.rust_type())?;
|
|
}
|
|
}
|
|
// If the return type is QString or QByteArray, append a pointer to the
|
|
// variable that will be set to the argument list. Also add a setter
|
|
// function.
|
|
if f.return_type.is_complex() {
|
|
writeln!(
|
|
r,
|
|
", d: *mut {}, set: fn(*mut {0}, str: *const c_char, len: c_int)) {{",
|
|
f.return_type.name()
|
|
)?;
|
|
} else {
|
|
writeln!(r, ") -> {} {{", f.return_type.rust_type())?;
|
|
}
|
|
for a in &f.arguments {
|
|
if a.argument_type.name() == "QString" {
|
|
writeln!(
|
|
r,
|
|
" let mut {} = String::new();
|
|
set_string_from_utf16(&mut {0}, {0}_str, {0}_len);",
|
|
a.name
|
|
)?;
|
|
} else if a.argument_type.name() == "QByteArray" {
|
|
writeln!(
|
|
r,
|
|
" let {} = {{ slice::from_raw_parts({0}_str as *const u8, to_usize({0}_len)) }};",
|
|
a.name
|
|
)?;
|
|
}
|
|
}
|
|
if f.mutable {
|
|
writeln!(r, " let o = &mut *ptr;")?;
|
|
} else {
|
|
writeln!(r, " let o = &*ptr;")?;
|
|
}
|
|
write!(r, " let r = o.{}(", lc)?;
|
|
for (i, a) in f.arguments.iter().enumerate() {
|
|
if i > 0 {
|
|
write!(r, ", ")?;
|
|
}
|
|
write!(r, "{}", a.name)?;
|
|
}
|
|
writeln!(r, ");")?;
|
|
if f.return_type.is_complex() {
|
|
writeln!(
|
|
r,
|
|
" let s: *const c_char = r.as_ptr() as (*const c_char);
|
|
set(d, s, r.len() as i32);"
|
|
)?;
|
|
} else {
|
|
writeln!(r, " r")?;
|
|
}
|
|
writeln!(r, "}}")
|
|
}
|
|
|
|
fn write_rust_interface_object(r: &mut Vec<u8>, o: &Object, conf: &Config) -> Result<()> {
|
|
let lcname = snake_case(&o.name);
|
|
writeln!(
|
|
r,
|
|
"
|
|
pub struct {}QObject {{}}
|
|
|
|
#[derive(Clone)]
|
|
pub struct {0}Emitter {{
|
|
qobject: Arc<Mutex<*const {0}QObject>>,",
|
|
o.name
|
|
)?;
|
|
for (name, p) in &o.properties {
|
|
if p.is_object() {
|
|
continue;
|
|
}
|
|
writeln!(
|
|
r,
|
|
" {}_changed: fn(*const {}QObject),",
|
|
snake_case(name),
|
|
o.name
|
|
)?;
|
|
}
|
|
if o.object_type == ObjectType::List {
|
|
writeln!(r, " new_data_ready: fn(*const {}QObject),", o.name)?;
|
|
} else if o.object_type == ObjectType::Tree {
|
|
writeln!(
|
|
r,
|
|
" new_data_ready: fn(*const {}QObject, index: COption<usize>),",
|
|
o.name
|
|
)?;
|
|
}
|
|
writeln!(
|
|
r,
|
|
"}}
|
|
|
|
unsafe impl Send for {}Emitter {{}}
|
|
|
|
impl {0}Emitter {{
|
|
fn clear(&self) {{
|
|
*self.qobject.lock().unwrap() = null();
|
|
}}",
|
|
o.name
|
|
)?;
|
|
|
|
for (name, p) in &o.properties {
|
|
if p.is_object() {
|
|
continue;
|
|
}
|
|
writeln!(
|
|
r,
|
|
" pub fn {}_changed(&self) {{
|
|
let ptr = *self.qobject.lock().unwrap();
|
|
if !ptr.is_null() {{
|
|
(self.{0}_changed)(ptr);
|
|
}}
|
|
}}",
|
|
snake_case(name)
|
|
)?;
|
|
}
|
|
|
|
if o.object_type == ObjectType::List {
|
|
writeln!(
|
|
r,
|
|
" pub fn new_data_ready(&self) {{
|
|
let ptr = *self.qobject.lock().unwrap();
|
|
if !ptr.is_null() {{
|
|
(self.new_data_ready)(ptr);
|
|
}}
|
|
}}"
|
|
)?;
|
|
} else if o.object_type == ObjectType::Tree {
|
|
writeln!(
|
|
r,
|
|
" pub fn new_data_ready(&self, item: Option<usize>) {{
|
|
let ptr = *self.qobject.lock().unwrap();
|
|
if !ptr.is_null() {{
|
|
(self.new_data_ready)(ptr, item.into());
|
|
}}
|
|
}}"
|
|
)?;
|
|
}
|
|
|
|
let mut model_struct = String::new();
|
|
if o.object_type != ObjectType::Object {
|
|
let type_ = if o.object_type == ObjectType::List {
|
|
"List"
|
|
} else {
|
|
"Tree"
|
|
};
|
|
model_struct = format!(", model: {}{}", o.name, type_);
|
|
let mut index = "";
|
|
let mut index_decl = "";
|
|
let mut index_c_decl = "";
|
|
let mut dest = "";
|
|
let mut dest_decl = "";
|
|
let mut dest_c_decl = "";
|
|
if o.object_type == ObjectType::Tree {
|
|
index_decl = " index: Option<usize>,";
|
|
index_c_decl = " index: COption<usize>,";
|
|
index = " index.into(),";
|
|
dest_decl = " dest: Option<usize>,";
|
|
dest_c_decl = " dest: COption<usize>,";
|
|
dest = " dest.into(),";
|
|
}
|
|
writeln!(
|
|
r,
|
|
"}}
|
|
|
|
#[derive(Clone)]
|
|
pub struct {0}{1} {{
|
|
qobject: *const {0}QObject,
|
|
layout_about_to_be_changed: fn(*const {0}QObject),
|
|
layout_changed: fn(*const {0}QObject),
|
|
data_changed: fn(*const {0}QObject, usize, usize),
|
|
begin_reset_model: fn(*const {0}QObject),
|
|
end_reset_model: fn(*const {0}QObject),
|
|
begin_insert_rows: fn(*const {0}QObject,{4} usize, usize),
|
|
end_insert_rows: fn(*const {0}QObject),
|
|
begin_move_rows: fn(*const {0}QObject,{4} usize, usize,{7} usize),
|
|
end_move_rows: fn(*const {0}QObject),
|
|
begin_remove_rows: fn(*const {0}QObject,{4} usize, usize),
|
|
end_remove_rows: fn(*const {0}QObject),
|
|
}}
|
|
|
|
impl {0}{1} {{
|
|
pub fn layout_about_to_be_changed(&self) {{
|
|
(self.layout_about_to_be_changed)(self.qobject);
|
|
}}
|
|
pub fn layout_changed(&self) {{
|
|
(self.layout_changed)(self.qobject);
|
|
}}
|
|
pub fn data_changed(&self, first: usize, last: usize) {{
|
|
(self.data_changed)(self.qobject, first, last);
|
|
}}
|
|
pub fn begin_reset_model(&self) {{
|
|
(self.begin_reset_model)(self.qobject);
|
|
}}
|
|
pub fn end_reset_model(&self) {{
|
|
(self.end_reset_model)(self.qobject);
|
|
}}
|
|
pub fn begin_insert_rows(&self,{2} first: usize, last: usize) {{
|
|
(self.begin_insert_rows)(self.qobject,{3} first, last);
|
|
}}
|
|
pub fn end_insert_rows(&self) {{
|
|
(self.end_insert_rows)(self.qobject);
|
|
}}
|
|
pub fn begin_move_rows(&self,{2} first: usize, last: usize,{5} destination: usize) {{
|
|
(self.begin_move_rows)(self.qobject,{3} first, last,{6} destination);
|
|
}}
|
|
pub fn end_move_rows(&self) {{
|
|
(self.end_move_rows)(self.qobject);
|
|
}}
|
|
pub fn begin_remove_rows(&self,{2} first: usize, last: usize) {{
|
|
(self.begin_remove_rows)(self.qobject,{3} first, last);
|
|
}}
|
|
pub fn end_remove_rows(&self) {{
|
|
(self.end_remove_rows)(self.qobject);
|
|
}}",
|
|
o.name, type_, index_decl, index, index_c_decl, dest_decl, dest, dest_c_decl
|
|
)?;
|
|
}
|
|
|
|
write!(
|
|
r,
|
|
"}}
|
|
|
|
pub trait {}Trait {{
|
|
fn new(emit: {0}Emitter{}",
|
|
o.name, model_struct
|
|
)?;
|
|
for (name, p) in &o.properties {
|
|
if p.is_object() {
|
|
write!(r, ",\n {}: {}", snake_case(name), p.type_name())?;
|
|
}
|
|
}
|
|
writeln!(
|
|
r,
|
|
") -> Self;
|
|
fn emit(&self) -> &{}Emitter;",
|
|
o.name
|
|
)?;
|
|
for (name, p) in &o.properties {
|
|
let lc = snake_case(name).to_lowercase();
|
|
if p.is_object() {
|
|
writeln!(r, " fn {}(&self) -> &{};", lc, rust_type(p))?;
|
|
writeln!(r, " fn {}_mut(&mut self) -> &mut {};", lc, rust_type(p))?;
|
|
} else {
|
|
if p.rust_by_function {
|
|
write!(
|
|
r,
|
|
" fn {}<F>(&self, getter: F) where F: FnOnce({});",
|
|
lc,
|
|
rust_return_type(p)
|
|
)?;
|
|
} else {
|
|
writeln!(r, " fn {}(&self) -> {};", lc, rust_return_type(p))?;
|
|
}
|
|
if p.write {
|
|
if p.type_name() == "QByteArray" {
|
|
if p.optional {
|
|
writeln!(r, " fn set_{}(&mut self, value: Option<&[u8]>);", lc)?;
|
|
} else {
|
|
writeln!(r, " fn set_{}(&mut self, value: &[u8]);", lc)?;
|
|
}
|
|
} else {
|
|
writeln!(r, " fn set_{}(&mut self, value: {});", lc, rust_type(p))?;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (name, f) in &o.functions {
|
|
let lc = snake_case(name);
|
|
let mut arg_list = String::new();
|
|
if !f.arguments.is_empty() {
|
|
for a in &f.arguments {
|
|
let t = if a.argument_type.name() == "QByteArray" {
|
|
"&[u8]"
|
|
} else {
|
|
a.argument_type.rust_type()
|
|
};
|
|
arg_list.push_str(&format!(", {}: {}", a.name, t));
|
|
}
|
|
}
|
|
writeln!(
|
|
r,
|
|
" fn {}(&{}self{}) -> {};",
|
|
lc,
|
|
if f.mutable { "mut " } else { "" },
|
|
arg_list,
|
|
f.return_type.rust_type()
|
|
)?;
|
|
}
|
|
if o.object_type == ObjectType::List {
|
|
writeln!(
|
|
r,
|
|
" fn row_count(&self) -> usize;
|
|
fn insert_rows(&mut self, _row: usize, _count: usize) -> bool {{ false }}
|
|
fn remove_rows(&mut self, _row: usize, _count: usize) -> bool {{ false }}
|
|
fn can_fetch_more(&self) -> bool {{
|
|
false
|
|
}}
|
|
fn fetch_more(&mut self) {{}}
|
|
fn sort(&mut self, u8, SortOrder) {{}}"
|
|
)?;
|
|
} else if o.object_type == ObjectType::Tree {
|
|
writeln!(
|
|
r,
|
|
" fn row_count(&self, Option<usize>) -> usize;
|
|
fn can_fetch_more(&self, Option<usize>) -> bool {{
|
|
false
|
|
}}
|
|
fn fetch_more(&mut self, Option<usize>) {{}}
|
|
fn sort(&mut self, u8, SortOrder) {{}}
|
|
fn check_row(&self, index: usize, row: usize) -> Option<usize>;
|
|
fn index(&self, item: Option<usize>, row: usize) -> usize;
|
|
fn parent(&self, index: usize) -> Option<usize>;
|
|
fn row(&self, index: usize) -> usize;"
|
|
)?;
|
|
}
|
|
if o.object_type != ObjectType::Object {
|
|
for (name, ip) in &o.item_properties {
|
|
let name = snake_case(name);
|
|
writeln!(
|
|
r,
|
|
" fn {}(&self, index: usize) -> {};",
|
|
name,
|
|
rust_return_type_(ip)
|
|
)?;
|
|
if ip.write {
|
|
if ip.item_property_type.name() == "QByteArray" {
|
|
if ip.optional {
|
|
writeln!(
|
|
r,
|
|
" fn set_{}(&mut self, index: usize, Option<&[u8]>) -> bool;",
|
|
name
|
|
)?;
|
|
} else {
|
|
writeln!(
|
|
r,
|
|
" fn set_{}(&mut self, index: usize, &[u8]) -> bool;",
|
|
name
|
|
)?;
|
|
}
|
|
} else {
|
|
writeln!(
|
|
r,
|
|
" fn set_{}(&mut self, index: usize, {}) -> bool;",
|
|
name,
|
|
rust_type_(ip)
|
|
)?;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
writeln!(
|
|
r,
|
|
"}}
|
|
|
|
#[no_mangle]
|
|
pub extern \"C\" fn {}_new(",
|
|
lcname
|
|
)?;
|
|
r_constructor_args_decl(r, &lcname, o, conf)?;
|
|
writeln!(r, ",\n) -> *mut {} {{", o.name)?;
|
|
r_constructor_args(r, &lcname, o, conf)?;
|
|
writeln!(
|
|
r,
|
|
" Box::into_raw(Box::new(d_{}))
|
|
}}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {0}_free(ptr: *mut {}) {{
|
|
Box::from_raw(ptr).emit().clear();
|
|
}}",
|
|
lcname, o.name
|
|
)?;
|
|
|
|
for (name, p) in &o.properties {
|
|
let base = format!("{}_{}", lcname, snake_case(name));
|
|
if p.is_object() {
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {}_get(ptr: *mut {}) -> *mut {} {{
|
|
(&mut *ptr).{}_mut()
|
|
}}",
|
|
base,
|
|
o.name,
|
|
rust_type(p),
|
|
snake_case(name)
|
|
)?;
|
|
} else if p.is_complex() && !p.optional {
|
|
if p.rust_by_function {
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {}_get(
|
|
ptr: *const {},
|
|
p: *mut {},
|
|
set: fn(*mut {2}, *const c_char, c_int),
|
|
) {{
|
|
let o = &*ptr;
|
|
o.{}(|v| {{
|
|
let s: *const c_char = v.as_ptr() as (*const c_char);
|
|
set(p, s, to_c_int(v.len()));
|
|
}});
|
|
}}",
|
|
base,
|
|
o.name,
|
|
p.type_name(),
|
|
snake_case(name)
|
|
)?;
|
|
} else {
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {}_get(
|
|
ptr: *const {},
|
|
p: *mut {},
|
|
set: fn(*mut {2}, *const c_char, c_int),
|
|
) {{
|
|
let o = &*ptr;
|
|
let v = o.{}();
|
|
let s: *const c_char = v.as_ptr() as (*const c_char);
|
|
set(p, s, to_c_int(v.len()));
|
|
}}",
|
|
base,
|
|
o.name,
|
|
p.type_name(),
|
|
snake_case(name)
|
|
)?;
|
|
}
|
|
if p.write && p.type_name() == "QString" {
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {}_set(ptr: *mut {}, v: *const c_ushort, len: c_int) {{
|
|
let o = &mut *ptr;
|
|
let mut s = String::new();
|
|
set_string_from_utf16(&mut s, v, len);
|
|
o.set_{}(s);
|
|
}}",
|
|
base,
|
|
o.name,
|
|
snake_case(name)
|
|
)?;
|
|
} else if p.write {
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {}_set(ptr: *mut {}, v: *const c_char, len: c_int) {{
|
|
let o = &mut *ptr;
|
|
let v = slice::from_raw_parts(v as *const u8, to_usize(len));
|
|
o.set_{}(v);
|
|
}}",
|
|
base,
|
|
o.name,
|
|
snake_case(name)
|
|
)?;
|
|
}
|
|
} else if p.is_complex() {
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {}_get(
|
|
ptr: *const {},
|
|
p: *mut {},
|
|
set: fn(*mut {2}, *const c_char, c_int),
|
|
) {{
|
|
let o = &*ptr;
|
|
let v = o.{}();
|
|
if let Some(v) = v {{
|
|
let s: *const c_char = v.as_ptr() as (*const c_char);
|
|
set(p, s, to_c_int(v.len()));
|
|
}}
|
|
}}",
|
|
base,
|
|
o.name,
|
|
p.type_name(),
|
|
snake_case(name)
|
|
)?;
|
|
if p.write && p.type_name() == "QString" {
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {}_set(ptr: *mut {}, v: *const c_ushort, len: c_int) {{
|
|
let o = &mut *ptr;
|
|
let mut s = String::new();
|
|
set_string_from_utf16(&mut s, v, len);
|
|
o.set_{}(Some(s));
|
|
}}",
|
|
base,
|
|
o.name,
|
|
snake_case(name)
|
|
)?;
|
|
} else if p.write {
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {}_set(ptr: *mut {}, v: *const c_char, len: c_int) {{
|
|
let o = &mut *ptr;
|
|
let v = slice::from_raw_parts(v as *const u8, to_usize(len));
|
|
o.set_{}(Some(v.into()));
|
|
}}",
|
|
base,
|
|
o.name,
|
|
snake_case(name)
|
|
)?;
|
|
}
|
|
} else if p.optional {
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {}_get(ptr: *const {}) -> COption<{}> {{
|
|
match (&*ptr).{}() {{
|
|
Some(value) => COption {{ data: value, some: true }},
|
|
None => COption {{ data: {2}::default(), some: false}}
|
|
}}
|
|
}}",
|
|
base,
|
|
o.name,
|
|
p.property_type.rust_type(),
|
|
snake_case(name)
|
|
)?;
|
|
if p.write {
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {}_set(ptr: *mut {}, v: {}) {{
|
|
(&mut *ptr).set_{}(Some(v));
|
|
}}",
|
|
base,
|
|
o.name,
|
|
p.property_type.rust_type(),
|
|
snake_case(name)
|
|
)?;
|
|
}
|
|
} else {
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {}_get(ptr: *const {}) -> {} {{
|
|
(&*ptr).{}()
|
|
}}",
|
|
base,
|
|
o.name,
|
|
rust_type(p),
|
|
snake_case(name)
|
|
)?;
|
|
if p.write {
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {}_set(ptr: *mut {}, v: {}) {{
|
|
(&mut *ptr).set_{}(v);
|
|
}}",
|
|
base,
|
|
o.name,
|
|
rust_type(p),
|
|
snake_case(name)
|
|
)?;
|
|
}
|
|
}
|
|
if p.write && p.optional {
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {}_set_none(ptr: *mut {}) {{
|
|
let o = &mut *ptr;
|
|
o.set_{}(None);
|
|
}}",
|
|
base,
|
|
o.name,
|
|
snake_case(name)
|
|
)?;
|
|
}
|
|
}
|
|
for f in &o.functions {
|
|
write_function(r, f, &lcname, o)?;
|
|
}
|
|
if o.object_type == ObjectType::List {
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {1}_row_count(ptr: *const {0}) -> c_int {{
|
|
to_c_int((&*ptr).row_count())
|
|
}}
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {1}_insert_rows(ptr: *mut {0}, row: c_int, count: c_int) -> bool {{
|
|
(&mut *ptr).insert_rows(to_usize(row), to_usize(count))
|
|
}}
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {1}_remove_rows(ptr: *mut {0}, row: c_int, count: c_int) -> bool {{
|
|
(&mut *ptr).remove_rows(to_usize(row), to_usize(count))
|
|
}}
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {1}_can_fetch_more(ptr: *const {0}) -> bool {{
|
|
(&*ptr).can_fetch_more()
|
|
}}
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {1}_fetch_more(ptr: *mut {0}) {{
|
|
(&mut *ptr).fetch_more()
|
|
}}
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {1}_sort(
|
|
ptr: *mut {0},
|
|
column: u8,
|
|
order: SortOrder,
|
|
) {{
|
|
(&mut *ptr).sort(column, order)
|
|
}}",
|
|
o.name, lcname
|
|
)?;
|
|
} else if o.object_type == ObjectType::Tree {
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {1}_row_count(
|
|
ptr: *const {0},
|
|
index: COption<usize>,
|
|
) -> c_int {{
|
|
to_c_int((&*ptr).row_count(index.into()))
|
|
}}
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {1}_can_fetch_more(
|
|
ptr: *const {0},
|
|
index: COption<usize>,
|
|
) -> bool {{
|
|
(&*ptr).can_fetch_more(index.into())
|
|
}}
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {1}_fetch_more(ptr: *mut {0}, index: COption<usize>) {{
|
|
(&mut *ptr).fetch_more(index.into())
|
|
}}
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {1}_sort(
|
|
ptr: *mut {0},
|
|
column: u8,
|
|
order: SortOrder
|
|
) {{
|
|
(&mut *ptr).sort(column, order)
|
|
}}
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {1}_check_row(
|
|
ptr: *const {0},
|
|
index: usize,
|
|
row: c_int,
|
|
) -> COption<usize> {{
|
|
(&*ptr).check_row(index.into(), to_usize(row)).into()
|
|
}}
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {1}_index(
|
|
ptr: *const {0},
|
|
index: COption<usize>,
|
|
row: c_int,
|
|
) -> usize {{
|
|
(&*ptr).index(index.into(), to_usize(row))
|
|
}}
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {1}_parent(ptr: *const {0}, index: usize) -> QModelIndex {{
|
|
if let Some(parent) = (&*ptr).parent(index) {{
|
|
QModelIndex {{
|
|
row: to_c_int((&*ptr).row(parent)),
|
|
internal_id: parent,
|
|
}}
|
|
}} else {{
|
|
QModelIndex {{
|
|
row: -1,
|
|
internal_id: 0,
|
|
}}
|
|
}}
|
|
}}
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {1}_row(ptr: *const {0}, index: usize) -> c_int {{
|
|
to_c_int((&*ptr).row(index))
|
|
}}",
|
|
o.name, lcname
|
|
)?;
|
|
}
|
|
if o.object_type != ObjectType::Object {
|
|
let (index_decl, index) = if o.object_type == ObjectType::Tree {
|
|
(", index: usize", "index")
|
|
} else {
|
|
(", row: c_int", "to_usize(row)")
|
|
};
|
|
for (name, ip) in &o.item_properties {
|
|
if ip.is_complex() && !ip.optional {
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {}_data_{}(
|
|
ptr: *const {}{},
|
|
d: *mut {},
|
|
set: fn(*mut {4}, *const c_char, len: c_int),
|
|
) {{
|
|
let o = &*ptr;
|
|
let data = o.{1}({});
|
|
let s: *const c_char = data.as_ptr() as (*const c_char);
|
|
set(d, s, to_c_int(data.len()));
|
|
}}",
|
|
lcname,
|
|
snake_case(name),
|
|
o.name,
|
|
index_decl,
|
|
ip.type_name(),
|
|
index
|
|
)?;
|
|
} else if ip.is_complex() {
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {}_data_{}(
|
|
ptr: *const {}{},
|
|
d: *mut {},
|
|
set: fn(*mut {4}, *const c_char, len: c_int),
|
|
) {{
|
|
let o = &*ptr;
|
|
let data = o.{1}({});
|
|
if let Some(data) = data {{
|
|
let s: *const c_char = data.as_ptr() as (*const c_char);
|
|
set(d, s, to_c_int(data.len()));
|
|
}}
|
|
}}",
|
|
lcname,
|
|
snake_case(name),
|
|
o.name,
|
|
index_decl,
|
|
ip.type_name(),
|
|
index
|
|
)?;
|
|
} else {
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {}_data_{}(ptr: *const {}{}) -> {} {{
|
|
let o = &*ptr;
|
|
o.{1}({}).into()
|
|
}}",
|
|
lcname,
|
|
snake_case(name),
|
|
o.name,
|
|
index_decl,
|
|
rust_c_type(ip),
|
|
index
|
|
)?;
|
|
}
|
|
if ip.write {
|
|
let val = if ip.optional { "Some(v)" } else { "v" };
|
|
if ip.type_name() == "QString" {
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {}_set_data_{}(
|
|
ptr: *mut {}{},
|
|
s: *const c_ushort, len: c_int,
|
|
) -> bool {{
|
|
let o = &mut *ptr;
|
|
let mut v = String::new();
|
|
set_string_from_utf16(&mut v, s, len);
|
|
o.set_{1}({}, {})
|
|
}}",
|
|
lcname,
|
|
snake_case(name),
|
|
o.name,
|
|
index_decl,
|
|
index,
|
|
val
|
|
)?;
|
|
} else if ip.type_name() == "QByteArray" {
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {}_set_data_{}(
|
|
ptr: *mut {}{},
|
|
s: *const c_char, len: c_int,
|
|
) -> bool {{
|
|
let o = &mut *ptr;
|
|
let slice = ::std::slice::from_raw_parts(s as *const u8, to_usize(len));
|
|
o.set_{1}({}, {})
|
|
}}",
|
|
lcname,
|
|
snake_case(name),
|
|
o.name,
|
|
index_decl,
|
|
index,
|
|
if ip.optional { "Some(slice)" } else { "slice" }
|
|
)?;
|
|
} else {
|
|
let type_ = ip.item_property_type.rust_type();
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {}_set_data_{}(
|
|
ptr: *mut {}{},
|
|
v: {},
|
|
) -> bool {{
|
|
(&mut *ptr).set_{1}({}, {})
|
|
}}",
|
|
lcname,
|
|
snake_case(name),
|
|
o.name,
|
|
index_decl,
|
|
type_,
|
|
index,
|
|
val
|
|
)?;
|
|
}
|
|
}
|
|
if ip.write && ip.optional {
|
|
writeln!(
|
|
r,
|
|
"
|
|
#[no_mangle]
|
|
pub unsafe extern \"C\" fn {}_set_data_{}_none(ptr: *mut {}{}) -> bool {{
|
|
(&mut *ptr).set_{1}({}, None)
|
|
}}",
|
|
lcname,
|
|
snake_case(name),
|
|
o.name,
|
|
index_decl,
|
|
index
|
|
)?;
|
|
}
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn write_rust_types(conf: &Config, r: &mut Vec<u8>) -> Result<()> {
|
|
let mut has_option = false;
|
|
let mut has_string = false;
|
|
let mut has_byte_array = false;
|
|
let mut has_list_or_tree = false;
|
|
|
|
for o in conf.objects.values() {
|
|
has_list_or_tree |= o.object_type != ObjectType::Object;
|
|
for p in o.properties.values() {
|
|
has_option |= p.optional;
|
|
has_string |= p.property_type == Type::Simple(SimpleType::QString);
|
|
has_byte_array |= p.property_type == Type::Simple(SimpleType::QByteArray);
|
|
}
|
|
for p in o.item_properties.values() {
|
|
has_option |= p.optional;
|
|
has_string |= p.item_property_type == SimpleType::QString;
|
|
has_byte_array |= p.item_property_type == SimpleType::QByteArray;
|
|
}
|
|
for f in o.functions.values() {
|
|
has_string |= f.return_type == SimpleType::QString;
|
|
has_byte_array |= f.return_type == SimpleType::QByteArray;
|
|
for a in &f.arguments {
|
|
has_string |= a.argument_type == SimpleType::QString;
|
|
has_byte_array |= a.argument_type == SimpleType::QByteArray;
|
|
}
|
|
}
|
|
}
|
|
|
|
if has_option || has_list_or_tree {
|
|
writeln!(
|
|
r,
|
|
"
|
|
|
|
#[repr(C)]
|
|
pub struct COption<T> {{
|
|
data: T,
|
|
some: bool,
|
|
}}
|
|
|
|
impl<T> COption<T> {{
|
|
#![allow(dead_code)]
|
|
fn into(self) -> Option<T> {{
|
|
if self.some {{
|
|
Some(self.data)
|
|
}} else {{
|
|
None
|
|
}}
|
|
}}
|
|
}}
|
|
|
|
impl<T> From<Option<T>> for COption<T>
|
|
where
|
|
T: Default,
|
|
{{
|
|
fn from(t: Option<T>) -> COption<T> {{
|
|
if let Some(v) = t {{
|
|
COption {{
|
|
data: v,
|
|
some: true,
|
|
}}
|
|
}} else {{
|
|
COption {{
|
|
data: T::default(),
|
|
some: false,
|
|
}}
|
|
}}
|
|
}}
|
|
}}"
|
|
)?;
|
|
}
|
|
if has_string {
|
|
writeln!(
|
|
r,
|
|
"
|
|
|
|
pub enum QString {{}}
|
|
|
|
fn set_string_from_utf16(s: &mut String, str: *const c_ushort, len: c_int) {{
|
|
let utf16 = unsafe {{ slice::from_raw_parts(str, to_usize(len)) }};
|
|
let characters = decode_utf16(utf16.iter().cloned())
|
|
.map(|r| r.unwrap());
|
|
s.clear();
|
|
s.extend(characters);
|
|
}}
|
|
"
|
|
)?;
|
|
}
|
|
if has_byte_array {
|
|
writeln!(
|
|
r,
|
|
"
|
|
|
|
pub enum QByteArray {{}}"
|
|
)?;
|
|
}
|
|
if has_list_or_tree {
|
|
writeln!(
|
|
r,
|
|
"
|
|
|
|
#[repr(C)]
|
|
#[derive(PartialEq, Eq, Debug)]
|
|
pub enum SortOrder {{
|
|
Ascending = 0,
|
|
Descending = 1,
|
|
}}
|
|
|
|
#[repr(C)]
|
|
pub struct QModelIndex {{
|
|
row: c_int,
|
|
internal_id: usize,
|
|
}}"
|
|
)?;
|
|
}
|
|
|
|
if has_string || has_byte_array || has_list_or_tree {
|
|
writeln!(
|
|
r,
|
|
"
|
|
|
|
fn to_usize(n: c_int) -> usize {{
|
|
if n < 0 {{
|
|
panic!(\"Cannot cast {{}} to usize\", n);
|
|
}}
|
|
n as usize
|
|
}}
|
|
"
|
|
)?;
|
|
}
|
|
|
|
if has_string || has_byte_array || has_list_or_tree {
|
|
writeln!(
|
|
r,
|
|
"
|
|
fn to_c_int(n: usize) -> c_int {{
|
|
if n > c_int::max_value() as usize {{
|
|
panic!(\"Cannot cast {{}} to c_int\", n);
|
|
}}
|
|
n as c_int
|
|
}}
|
|
"
|
|
)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub fn write_interface(conf: &Config) -> Result<()> {
|
|
let mut r = Vec::new();
|
|
writeln!(
|
|
r,
|
|
"/* generated by rust_qt_binding_generator */
|
|
#![allow(unknown_lints)]
|
|
#![allow(mutex_atomic, needless_pass_by_value)]
|
|
use libc::{{c_char, c_ushort, c_int}};
|
|
use std::slice;
|
|
use std::char::decode_utf16;
|
|
|
|
use std::sync::{{Arc, Mutex}};
|
|
use std::ptr::null;
|
|
|
|
use {}::*;",
|
|
conf.rust.implementation_module
|
|
)?;
|
|
|
|
write_rust_types(conf, &mut r)?;
|
|
|
|
for object in conf.objects.values() {
|
|
write_rust_interface_object(&mut r, object, conf)?;
|
|
}
|
|
let mut file = conf
|
|
.config_file
|
|
.parent()
|
|
.unwrap()
|
|
.join(&conf.rust.dir)
|
|
.join("src")
|
|
.join(&conf.rust.interface_module);
|
|
file.set_extension("rs");
|
|
write_if_different(file, &r)
|
|
}
|
|
|
|
fn write_rust_implementation_object(r: &mut Vec<u8>, o: &Object) -> Result<()> {
|
|
if o.object_type != ObjectType::Object {
|
|
writeln!(r, "#[derive(Default, Clone)]")?;
|
|
writeln!(r, "struct {}Item {{", o.name)?;
|
|
for (name, ip) in &o.item_properties {
|
|
let lc = snake_case(name);
|
|
if ip.optional {
|
|
writeln!(
|
|
r,
|
|
" {}: Option<{}>,",
|
|
lc,
|
|
ip.item_property_type.rust_type()
|
|
)?;
|
|
} else {
|
|
writeln!(r, " {}: {},", lc, ip.item_property_type.rust_type())?;
|
|
}
|
|
}
|
|
writeln!(r, "}}\n")?;
|
|
}
|
|
let mut model_struct = String::new();
|
|
writeln!(r, "pub struct {} {{\n emit: {0}Emitter,", o.name)?;
|
|
if o.object_type == ObjectType::List {
|
|
model_struct = format!(", model: {}List", o.name);
|
|
writeln!(r, " model: {}List,", o.name)?;
|
|
} else if o.object_type == ObjectType::Tree {
|
|
model_struct = format!(", model: {}Tree", o.name);
|
|
writeln!(r, " model: {}Tree,", o.name)?;
|
|
}
|
|
for (name, p) in &o.properties {
|
|
let lc = snake_case(name);
|
|
writeln!(r, " {}: {},", lc, rust_type(p))?;
|
|
}
|
|
if o.object_type != ObjectType::Object {
|
|
writeln!(r, " list: Vec<{}Item>,", o.name)?;
|
|
}
|
|
writeln!(r, "}}\n")?;
|
|
for (name, p) in &o.properties {
|
|
if p.is_object() {
|
|
model_struct += &format!(", {}: {}", name, p.type_name());
|
|
}
|
|
}
|
|
writeln!(
|
|
r,
|
|
"impl {}Trait for {0} {{
|
|
fn new(emit: {0}Emitter{}) -> {0} {{
|
|
{0} {{
|
|
emit,",
|
|
o.name, model_struct
|
|
)?;
|
|
if o.object_type != ObjectType::Object {
|
|
writeln!(r, " model,")?;
|
|
writeln!(r, " list: Vec::new(),")?;
|
|
}
|
|
for (name, p) in &o.properties {
|
|
let lc = snake_case(name);
|
|
if p.is_object() {
|
|
writeln!(r, " {},", lc)?;
|
|
} else {
|
|
writeln!(r, " {}: {},", lc, rust_type_init(p))?;
|
|
}
|
|
}
|
|
writeln!(
|
|
r,
|
|
" }}
|
|
}}
|
|
fn emit(&self) -> &{}Emitter {{
|
|
&self.emit
|
|
}}",
|
|
o.name
|
|
)?;
|
|
for (name, p) in &o.properties {
|
|
let lc = snake_case(name);
|
|
if p.is_object() {
|
|
writeln!(
|
|
r,
|
|
" fn {}(&self) -> &{} {{
|
|
&self.{0}
|
|
}}
|
|
fn {0}_mut(&mut self) -> &mut {1} {{
|
|
&mut self.{0}
|
|
}}",
|
|
lc,
|
|
rust_return_type(p)
|
|
)?;
|
|
} else if p.rust_by_function {
|
|
writeln!(
|
|
r,
|
|
" fn {}<F>(&self, getter: F)
|
|
where
|
|
F: FnOnce({}),
|
|
{{
|
|
getter(&self.{0})
|
|
}}",
|
|
lc,
|
|
rust_return_type(p)
|
|
)?;
|
|
} else {
|
|
writeln!(r, " fn {}(&self) -> {} {{", lc, rust_return_type(p))?;
|
|
if p.is_complex() {
|
|
if p.optional {
|
|
writeln!(r, " self.{}.as_ref().map(|p| &p[..])", lc)?;
|
|
} else {
|
|
writeln!(r, " &self.{}", lc)?;
|
|
}
|
|
} else {
|
|
writeln!(r, " self.{}", lc)?;
|
|
}
|
|
writeln!(r, " }}")?;
|
|
}
|
|
if !p.is_object() && p.write {
|
|
let bytearray = p.property_type == Type::Simple(SimpleType::QByteArray);
|
|
let (t, v) = if bytearray && p.optional {
|
|
("Option<&[u8]>".to_string(), ".map(|v| v.to_vec())")
|
|
} else if bytearray {
|
|
("&[u8]".to_string(), ".to_vec()")
|
|
} else {
|
|
(rust_type(p), "")
|
|
};
|
|
writeln!(
|
|
r,
|
|
" fn set_{}(&mut self, value: {}) {{
|
|
self.{0} = value{};
|
|
self.emit.{0}_changed();
|
|
}}",
|
|
lc, t, v
|
|
)?;
|
|
}
|
|
}
|
|
if o.object_type == ObjectType::List {
|
|
writeln!(
|
|
r,
|
|
" fn row_count(&self) -> usize {{\n self.list.len()\n }}"
|
|
)?;
|
|
} else if o.object_type == ObjectType::Tree {
|
|
writeln!(
|
|
r,
|
|
" fn row_count(&self, item: Option<usize>) -> usize {{
|
|
self.list.len()
|
|
}}
|
|
fn index(&self, item: Option<usize>, row: usize) -> usize {{
|
|
0
|
|
}}
|
|
fn parent(&self, index: usize) -> Option<usize> {{
|
|
None
|
|
}}
|
|
fn row(&self, index: usize) -> usize {{
|
|
index
|
|
}}
|
|
fn check_row(&self, index: usize, _row: usize) -> Option<usize> {{
|
|
if index < self.list.len() {{
|
|
Some(index)
|
|
}} else {{
|
|
None
|
|
}}
|
|
}}"
|
|
)?;
|
|
}
|
|
if o.object_type != ObjectType::Object {
|
|
for (name, ip) in &o.item_properties {
|
|
let lc = snake_case(name);
|
|
writeln!(
|
|
r,
|
|
" fn {}(&self, index: usize) -> {} {{",
|
|
lc,
|
|
rust_return_type_(ip)
|
|
)?;
|
|
if ip.is_complex() && ip.optional {
|
|
writeln!(
|
|
r,
|
|
" self.list[index].{}.as_ref().map(|v| &v[..])",
|
|
lc
|
|
)?;
|
|
} else if ip.is_complex() {
|
|
writeln!(r, " &self.list[index].{}", lc)?;
|
|
} else {
|
|
writeln!(r, " self.list[index].{}", lc)?;
|
|
}
|
|
writeln!(r, " }}")?;
|
|
let bytearray = ip.item_property_type == SimpleType::QByteArray;
|
|
if ip.write && bytearray && ip.optional {
|
|
writeln!(
|
|
r,
|
|
" fn set_{}(&mut self, index: usize, v: Option<&[u8]>) -> bool {{
|
|
self.list[index].{0} = v.map(|v| v.to_vec());
|
|
true
|
|
}}",
|
|
lc
|
|
)?;
|
|
} else if ip.write && bytearray {
|
|
writeln!(
|
|
r,
|
|
" fn set_{}(&mut self, index: usize, v: &[u8]) -> bool {{
|
|
self.list[index].{0} = v.to_vec();
|
|
true
|
|
}}",
|
|
lc
|
|
)?;
|
|
} else if ip.write {
|
|
writeln!(
|
|
r,
|
|
" fn set_{}(&mut self, index: usize, v: {}) -> bool {{
|
|
self.list[index].{0} = v;
|
|
true
|
|
}}",
|
|
lc,
|
|
rust_type_(ip)
|
|
)?;
|
|
}
|
|
}
|
|
}
|
|
writeln!(r, "}}")
|
|
}
|
|
|
|
pub fn write_implementation(conf: &Config) -> Result<()> {
|
|
let mut file = conf
|
|
.config_file
|
|
.parent()
|
|
.unwrap()
|
|
.join(&conf.rust.dir)
|
|
.join("src")
|
|
.join(&conf.rust.implementation_module);
|
|
if !conf.overwrite_implementation && file.exists() {
|
|
return Ok(());
|
|
}
|
|
file.set_extension("rs");
|
|
if !conf.overwrite_implementation && file.exists() {
|
|
return Ok(());
|
|
}
|
|
let mut r = Vec::new();
|
|
writeln!(
|
|
r,
|
|
"#![allow(unused_imports)]
|
|
#![allow(unused_variables)]
|
|
#![allow(dead_code)]
|
|
use {}::*;
|
|
",
|
|
conf.rust.interface_module
|
|
)?;
|
|
|
|
for object in conf.objects.values() {
|
|
write_rust_implementation_object(&mut r, object)?;
|
|
}
|
|
write_if_different(file, &r)
|
|
}
|