Return strings and bytearrays by reference by default in the rust code

master
Jos van den Oever 2017-08-30 21:58:01 +02:00
parent f2532a36d6
commit f7ad9a9d5c
20 changed files with 274 additions and 72 deletions

View File

@ -1,8 +1,87 @@
# Rust Qt Bindings Generator
# Rust Qt Binding Generator
![Rust Qt Bindings](logo.svg)
![Rust Qt Binding](logo.svg)
This generator gets you started quickly to use Rust code from Qt and QML.
This code generator gets you started quickly to use Rust code from Qt and QML. In other words, it helps to create a Qt based GUI on top of Rust code.
Qt is a mature cross-platform graphical user interface library. Rust is a new programming language with strong compile time checks and a modern syntax.
To combine Qt and Rust, write an interface in a JSON file. From that, the generator creates Qt code and Rust code. The Qt code can be used directly. The Rust code has two files: interface and implementation. The interface can be used directly.
```json
{
"cppFile": "src/person.cpp",
"rust": {
"dir": "rust",
"interfaceModule": "interface",
"implementationModule": "implementation"
},
"objects": {
"Person": {
"type": "Object",
"properties": {
"name": {
"type": "QString",
"write": true
}
}
}
}
}
```
This file describes an binding with one object, `Person`. `Person` has one property: `name`. It is a writable property.
The Rust Qt Binding Generator will create binding source code from this description:
```bash
rust_qt_binding_generator binding.json
```
This will create four files:
* *src/person.h*
* *src/person.cpp*
* rust/src/implemenation.rs
* *rust/src/interface.rs*
Only `implementation.rs` should be changed. The other files are the binding. `implementation.rs` is initialy created with a simple implementation that is shown here with some comments.
```rust
use interface::*;
/// A Person
pub struct Person {
/// Emit signals the the Qt code.
emit: PersonEmitter,
/// The name of the person.
name: String,
}
/// Implementation of the binding
impl PersonTrait for Person {
/// Create a new person with default data.
fn create(emit: PersonEmitter) -> Person {
Person {
emit: emit,
name: String::new(),
}
}
/// The emitter can emit signals to the Qt code.
fn emit(&self) -> &PersonEmitter {
&self.emit
}
/// Get the name of the Person
fn get_name(&self) -> String {
self.name.clone()
}
/// Set the name of the Person
fn set_name(&mut self, value: String) {
self.name = value;
self.emit.name_changed();
}
}
```
The building block of Qt and QML projects are QObject and the Model View classes. `rust_qt_binding_generator` reads a json file to generate QObject or QAbstractItemModel classes that call into generated Rust files. For each type from the JSON file, a Rust trait is generated that should be implemented.

View File

@ -38,7 +38,8 @@
"type": "quint8"
},
"cmd": {
"type": "QString"
"type": "QString",
"rustByValue": true
}
}
}

View File

@ -13,6 +13,7 @@ pub struct DirEntry {
name: OsString,
metadata: Option<Metadata>,
path: Option<PathBuf>,
icon: Vec<u8>,
}
type Incoming<T> = Arc<Mutex<HashMap<usize, Vec<T>>>>;
@ -23,6 +24,7 @@ impl Item for DirEntry {
name: OsString::from(name),
metadata: metadata(name).ok(),
path: None,
icon: Vec::new()
}
}
fn can_fetch_more(&self) -> bool {
@ -43,6 +45,9 @@ impl Item for DirEntry {
fn file_size(&self) -> Option<u64> {
self.metadata.as_ref().map(|m| m.len())
}
fn icon(&self) -> &[u8] {
&self.icon
}
fn retrieve(id: usize, parents: Vec<&DirEntry>, q: Incoming<Self>, emit: TreeEmitter) {
let mut v = Vec::new();
let path: PathBuf = parents.into_iter().map(|e| &e.name).collect();
@ -53,6 +58,7 @@ impl Item for DirEntry {
name: i.file_name(),
metadata: i.metadata().ok(),
path: Some(i.path()),
icon: Vec::new(),
};
v.push(de);
}
@ -73,6 +79,7 @@ impl Default for DirEntry {
name: OsString::new(),
metadata: None,
path: None,
icon: Vec::new(),
}
}
}
@ -86,6 +93,7 @@ pub trait Item: Default {
fn file_permissions(&self) -> i32;
fn file_type(&self) -> i32;
fn file_size(&self) -> Option<u64>;
fn icon(&self) -> &[u8];
}
pub type Tree = RGeneralItemModel<DirEntry>;
@ -195,8 +203,8 @@ where
fn emit(&self) -> &TreeEmitter {
&self.emit
}
fn get_path(&self) -> Option<String> {
self.path.clone()
fn get_path(&self) -> Option<&str> {
self.path.as_ref().map(|s|&s[..])
}
fn set_path(&mut self, value: Option<String>) {
if self.path != value {
@ -261,8 +269,8 @@ where
self.get(item).data.file_permissions()
}
#[allow(unused_variables)]
fn file_icon(&self, item: usize) -> Vec<u8> {
Vec::new()
fn file_icon(&self, item: usize) -> &[u8] {
self.get(item).data.icon()
}
fn file_path(&self, item: usize) -> Option<String> {
self.get(item).data.file_path()

View File

@ -55,6 +55,15 @@ impl QStringIn {
}
}
impl<'a> From<&'a str> for QString {
fn from(string: &'a str) -> QString {
QString {
len: string.len() as c_int,
data: string.as_ptr(),
}
}
}
impl<'a> From<&'a String> for QString {
fn from(string: &'a String) -> QString {
QString {
@ -78,8 +87,8 @@ impl QByteArray {
}
}
impl<'a> From<&'a Vec<u8>> for QByteArray {
fn from(value: &'a Vec<u8>) -> QByteArray {
impl<'a> From<&'a [u8]> for QByteArray {
fn from(value: &'a [u8]) -> QByteArray {
QByteArray {
len: value.len() as c_int,
data: value.as_ptr(),
@ -167,7 +176,7 @@ impl TreeUniformTree {
pub trait TreeTrait {
fn create(emit: TreeEmitter, model: TreeUniformTree) -> Self;
fn emit(&self) -> &TreeEmitter;
fn get_path(&self) -> Option<String>;
fn get_path(&self) -> Option<&str>;
fn set_path(&mut self, value: Option<String>);
fn row_count(&self, Option<usize>) -> usize;
fn can_fetch_more(&self, Option<usize>) -> bool {
@ -178,7 +187,7 @@ pub trait TreeTrait {
fn index(&self, item: Option<usize>, row: usize) -> usize;
fn parent(&self, item: usize) -> Option<usize>;
fn row(&self, item: usize) -> usize;
fn file_icon(&self, item: usize) -> Vec<u8>;
fn file_icon(&self, item: usize) -> &[u8];
fn file_name(&self, item: usize) -> String;
fn file_path(&self, item: usize) -> Option<String>;
fn file_permissions(&self, item: usize) -> i32;
@ -231,7 +240,7 @@ pub unsafe extern "C" fn tree_path_get(
) {
let data = (&*ptr).get_path();
if let Some(data) = data {
set(p, QString::from(&data));
set(p, data.into());
}
}
@ -323,7 +332,7 @@ pub unsafe extern "C" fn tree_data_file_icon(
set: fn(*mut c_void, QByteArray),
) {
let data = (&*ptr).file_icon(item);
set(d, QByteArray::from(&data));
set(d, (data).into());
}
#[no_mangle]
@ -333,7 +342,7 @@ pub unsafe extern "C" fn tree_data_file_name(
set: fn(*mut c_void, QString),
) {
let data = (&*ptr).file_name(item);
set(d, QString::from(&data));
set(d, (&data).into());
}
#[no_mangle]

View File

@ -361,8 +361,8 @@ impl ProcessesTrait for Processes {
fn memory(&self, item: usize) -> u64 {
self.process(item).memory
}
fn name(&self, item: usize) -> String {
self.process(item).name.clone()
fn name(&self, item: usize) -> &str {
&self.process(item).name
}
fn cmd(&self, item: usize) -> String {
self.process(item).cmd.join(" ")

View File

@ -55,6 +55,15 @@ impl QStringIn {
}
}
impl<'a> From<&'a str> for QString {
fn from(string: &'a str) -> QString {
QString {
len: string.len() as c_int,
data: string.as_ptr(),
}
}
}
impl<'a> From<&'a String> for QString {
fn from(string: &'a String) -> QString {
QString {
@ -159,7 +168,7 @@ pub trait ProcessesTrait {
fn cpu_percentage(&self, item: usize) -> u8;
fn cpu_usage(&self, item: usize) -> f32;
fn memory(&self, item: usize) -> u64;
fn name(&self, item: usize) -> String;
fn name(&self, item: usize) -> &str;
fn pid(&self, item: usize) -> u32;
fn uid(&self, item: usize) -> u32;
}
@ -290,7 +299,7 @@ pub unsafe extern "C" fn processes_data_cmd(
set: fn(*mut c_void, QString),
) {
let data = (&*ptr).cmd(item);
set(d, QString::from(&data));
set(d, (&data).into());
}
#[no_mangle]
@ -315,7 +324,7 @@ pub unsafe extern "C" fn processes_data_name(
set: fn(*mut c_void, QString),
) {
let data = (&*ptr).name(item);
set(d, QString::from(&data));
set(d, (data).into());
}
#[no_mangle]

View File

@ -18,7 +18,8 @@
"itemProperties": {
"fileName": {
"type": "QString",
"roles": [ ["display"] ]
"roles": [ ["display"] ],
"rustByValue": true
},
"fileIcon": {
"type": "QByteArray",
@ -32,7 +33,8 @@
"filePath": {
"type": "QString",
"optional": true,
"roles": [ [], [], ["display"] ]
"roles": [ [], [], ["display"] ],
"rustByValue": true
},
"filePermissions": {
"type": "qint32",

View File

@ -12,7 +12,7 @@ BindingTypeProperties simpleType(BindingType type, const char* name, const char*
.cppSetType = name,
.cSetType = name,
.rustType = name,
.rustTypeInit = init,
.rustTypeInit = init
};
}
@ -105,6 +105,7 @@ parseProperty(const QString& name, const QJsonObject& json) {
p.type = parseBindingType(json.value("type").toString());
p.write = json.value("write").toBool();
p.optional = json.value("optional").toBool();
p.rustByValue = json.value("rustByValue").toBool();
return p;
}
@ -129,6 +130,7 @@ parseItemProperty(const QString& name, const QJsonObject& json) {
ip.type = parseBindingType(json.value("type").toString());
ip.write = json.value("write").toBool();
ip.optional = json.value("optional").toBool();
ip.rustByValue = json.value("rustByValue").toBool();
QJsonArray roles = json.value("roles").toArray();
for (auto r: roles) {
QList<Qt::ItemDataRole> l;

View File

@ -10,6 +10,25 @@ QString rustType(const T& p)
return p.type.rustType;
}
template <typename T>
QString rustReturnType(const T& p)
{
QString type = p.type.rustType;
if (type == "String" && !p.rustByValue) {
type = "str";
}
if (type == "Vec<u8>" && !p.rustByValue) {
type = "[u8]";
}
if (p.type.isComplex() && !p.rustByValue) {
type = "&" + type;
}
if (p.optional) {
return "Option<" + type + ">";
}
return type;
}
template <typename T>
QString rustCType(const T& p)
{
@ -235,7 +254,7 @@ pub trait %1Trait {
r << QString(" fn get_%1(&self) -> &%2;\n").arg(lc, rustType(p));
r << QString(" fn get_mut_%1(&mut self) -> &mut %2;\n").arg(lc, rustType(p));
} else {
r << QString(" fn get_%1(&self) -> %2;\n").arg(lc, rustType(p));
r << QString(" fn get_%1(&self) -> %2;\n").arg(lc, rustReturnType(p));
if (p.write) {
r << QString(" fn set_%1(&mut self, value: %2);\n").arg(lc, rustType(p));
}
@ -264,7 +283,7 @@ pub trait %1Trait {
if (o.type != ObjectType::Object) {
for (auto ip: o.itemProperties) {
r << QString(" fn %1(&self, item: usize) -> %2;\n")
.arg(snakeCase(ip.name), rustType(ip));
.arg(snakeCase(ip.name), rustReturnType(ip));
if (ip.write) {
r << QString(" fn set_%1(&mut self, item: usize, %2) -> bool;\n")
.arg(snakeCase(ip.name), rustType(ip));
@ -308,9 +327,10 @@ pub unsafe extern "C" fn %2_get(
set: fn(*mut c_void, %4),
) {
let data = (&*ptr).get_%3();
set(p, %4::from(&data));
set(p, %5data.into());
}
)").arg(o.name, base, snakeCase(p.name), p.type.name);
)").arg(o.name, base, snakeCase(p.name), p.type.name,
p.rustByValue ?"&" :"");
if (p.write) {
const QString type = p.type.name == "QString" ? "QStringIn" : p.type.name;
r << QString(R"(
@ -330,10 +350,11 @@ pub unsafe extern "C" fn %2_get(
) {
let data = (&*ptr).get_%3();
if let Some(data) = data {
set(p, %4::from(&data));
set(p, %5data.into());
}
}
)").arg(o.name, base, snakeCase(p.name), p.type.name);
)").arg(o.name, base, snakeCase(p.name), p.type.name,
p.rustByValue ?"&" :"");
if (p.write) {
const QString type = p.type.name == "QString" ? "QStringIn" : p.type.name;
r << QString(R"(
@ -479,9 +500,10 @@ pub unsafe extern "C" fn %2_data_%3(
set: fn(*mut c_void, %4),
) {
let data = (&*ptr).%3(%6);
set(d, %4::from(&data));
set(d, (%7data).into());
}
)").arg(o.name, lcname, snakeCase(ip.name), ip.type.name, indexDecl, index);
)").arg(o.name, lcname, snakeCase(ip.name), ip.type.name, indexDecl, index,
ip.rustByValue ?"&" :"");
} else if (ip.type.isComplex()) {
r << QString(R"(
#[no_mangle]
@ -616,6 +638,15 @@ impl QStringIn {
}
}
impl<'a> From<&'a str> for QString {
fn from(string: &'a str) -> QString {
QString {
len: string.len() as c_int,
data: string.as_ptr(),
}
}
}
impl<'a> From<&'a String> for QString {
fn from(string: &'a String) -> QString {
QString {
@ -642,8 +673,8 @@ impl QByteArray {
}
}
impl<'a> From<&'a Vec<u8>> for QByteArray {
fn from(value: &'a Vec<u8>) -> QByteArray {
impl<'a> From<&'a [u8]> for QByteArray {
fn from(value: &'a [u8]) -> QByteArray {
QByteArray {
len: value.len() as c_int,
data: value.as_ptr(),
@ -760,11 +791,21 @@ void writeRustImplementationObject(QTextStream& r, const Object& o) {
fn get_mut_%1(&mut self) -> &mut %2 {
&mut self.%1
}
)").arg(lc, rustType(p));
)").arg(lc, rustReturnType(p));
} else {
r << QString(" fn get_%1(&self) -> %2 {\n").arg(lc, rustType(p));
r << QString(" fn get_%1(&self) -> %2 {\n").arg(lc, rustReturnType(p));
if (p.type.isComplex()) {
r << QString(" self.%1.clone()\n").arg(lc);
if (p.optional) {
/*
if (rustType(p) == "Option<String>") {
r << QString(" self.%1.as_ref().map(|p|p.as_str())\n").arg(lc);
} else {
}
*/
r << QString(" self.%1.as_ref().map(|p|&p[..])\n").arg(lc);
} else {
r << QString(" &self.%1\n").arg(lc);
}
} else {
r << QString(" self.%1\n").arg(lc);
}
@ -803,8 +844,12 @@ void writeRustImplementationObject(QTextStream& r, const Object& o) {
for (auto ip: o.itemProperties) {
const QString lc(snakeCase(ip.name));
r << QString(" fn %1(&self, item: usize) -> %2 {\n")
.arg(lc, rustType(ip));
r << " self.list[item]." << lc << ".clone()\n";
.arg(lc, rustReturnType(ip));
if (ip.type.isComplex()) {
r << " &self.list[item]." << lc << "\n";
} else {
r << " self.list[item]." << lc << "\n";
}
r << " }\n";
if (ip.write) {
r << QString(" fn set_%1(&mut self, item: usize, v: %2) -> bool {\n")

View File

@ -41,6 +41,7 @@ struct Property {
BindingTypeProperties type;
bool write;
bool optional;
bool rustByValue;
};
struct ItemProperty {
@ -48,6 +49,7 @@ struct ItemProperty {
BindingTypeProperties type;
bool write;
bool optional;
bool rustByValue;
QList<QList<Qt::ItemDataRole>> roles;
};

View File

@ -28,8 +28,8 @@ impl PersonsTrait for Persons {
fn row_count(&self) -> usize {
self.list.len()
}
fn user_name(&self, item: usize) -> String {
self.list[item].user_name.clone()
fn user_name(&self, item: usize) -> &str {
&self.list[item].user_name
}
fn set_user_name(&mut self, item: usize, v: String) -> bool {
self.list[item].user_name = v;

View File

@ -55,6 +55,15 @@ impl QStringIn {
}
}
impl<'a> From<&'a str> for QString {
fn from(string: &'a str) -> QString {
QString {
len: string.len() as c_int,
data: string.as_ptr(),
}
}
}
impl<'a> From<&'a String> for QString {
fn from(string: &'a String) -> QString {
QString {
@ -143,7 +152,7 @@ pub trait PersonsTrait {
}
fn fetch_more(&mut self) {}
fn sort(&mut self, u8, SortOrder) {}
fn user_name(&self, item: usize) -> String;
fn user_name(&self, item: usize) -> &str;
fn set_user_name(&mut self, item: usize, String) -> bool;
}
@ -210,7 +219,7 @@ pub unsafe extern "C" fn persons_data_user_name(
set: fn(*mut c_void, QString),
) {
let data = (&*ptr).user_name(row as usize);
set(d, QString::from(&data));
set(d, (data).into());
}
#[no_mangle]

View File

@ -18,8 +18,8 @@ impl PersonTrait for Person {
fn emit(&self) -> &PersonEmitter {
&self.emit
}
fn get_user_name(&self) -> String {
self.user_name.clone()
fn get_user_name(&self) -> &str {
&self.user_name
}
fn set_user_name(&mut self, value: String) {
self.user_name = value;

View File

@ -29,6 +29,15 @@ impl QStringIn {
}
}
impl<'a> From<&'a str> for QString {
fn from(string: &'a str) -> QString {
QString {
len: string.len() as c_int,
data: string.as_ptr(),
}
}
}
impl<'a> From<&'a String> for QString {
fn from(string: &'a String) -> QString {
QString {
@ -63,7 +72,7 @@ impl PersonEmitter {
pub trait PersonTrait {
fn create(emit: PersonEmitter) -> Self;
fn emit(&self) -> &PersonEmitter;
fn get_user_name(&self) -> String;
fn get_user_name(&self) -> &str;
fn set_user_name(&mut self, value: String);
}
@ -92,7 +101,7 @@ pub unsafe extern "C" fn person_user_name_get(
set: fn(*mut c_void, QString),
) {
let data = (&*ptr).get_user_name();
set(p, QString::from(&data));
set(p, data.into());
}
#[no_mangle]

View File

@ -39,8 +39,8 @@ impl ObjectTrait for Object {
self.boolean = value;
self.emit.boolean_changed();
}
fn get_bytearray(&self) -> Vec<u8> {
self.bytearray.clone()
fn get_bytearray(&self) -> &[u8] {
&self.bytearray
}
fn set_bytearray(&mut self, value: Vec<u8>) {
self.bytearray = value;
@ -53,22 +53,22 @@ impl ObjectTrait for Object {
self.integer = value;
self.emit.integer_changed();
}
fn get_optional_bytearray(&self) -> Option<Vec<u8>> {
self.optional_bytearray.clone()
fn get_optional_bytearray(&self) -> Option<&[u8]> {
self.optional_bytearray.as_ref().map(|p|&p[..])
}
fn set_optional_bytearray(&mut self, value: Option<Vec<u8>>) {
self.optional_bytearray = value;
self.emit.optional_bytearray_changed();
}
fn get_optional_string(&self) -> Option<String> {
self.optional_string.clone()
fn get_optional_string(&self) -> Option<&str> {
self.optional_string.as_ref().map(|p|&p[..])
}
fn set_optional_string(&mut self, value: Option<String>) {
self.optional_string = value;
self.emit.optional_string_changed();
}
fn get_string(&self) -> String {
self.string.clone()
fn get_string(&self) -> &str {
&self.string
}
fn set_string(&mut self, value: String) {
self.string = value;

View File

@ -55,6 +55,15 @@ impl QStringIn {
}
}
impl<'a> From<&'a str> for QString {
fn from(string: &'a str) -> QString {
QString {
len: string.len() as c_int,
data: string.as_ptr(),
}
}
}
impl<'a> From<&'a String> for QString {
fn from(string: &'a String) -> QString {
QString {
@ -78,8 +87,8 @@ impl QByteArray {
}
}
impl<'a> From<&'a Vec<u8>> for QByteArray {
fn from(value: &'a Vec<u8>) -> QByteArray {
impl<'a> From<&'a [u8]> for QByteArray {
fn from(value: &'a [u8]) -> QByteArray {
QByteArray {
len: value.len() as c_int,
data: value.as_ptr(),
@ -163,15 +172,15 @@ pub trait ObjectTrait {
fn emit(&self) -> &ObjectEmitter;
fn get_boolean(&self) -> bool;
fn set_boolean(&mut self, value: bool);
fn get_bytearray(&self) -> Vec<u8>;
fn get_bytearray(&self) -> &[u8];
fn set_bytearray(&mut self, value: Vec<u8>);
fn get_integer(&self) -> i32;
fn set_integer(&mut self, value: i32);
fn get_optional_bytearray(&self) -> Option<Vec<u8>>;
fn get_optional_bytearray(&self) -> Option<&[u8]>;
fn set_optional_bytearray(&mut self, value: Option<Vec<u8>>);
fn get_optional_string(&self) -> Option<String>;
fn get_optional_string(&self) -> Option<&str>;
fn set_optional_string(&mut self, value: Option<String>);
fn get_string(&self) -> String;
fn get_string(&self) -> &str;
fn set_string(&mut self, value: String);
fn get_u64(&self) -> u64;
fn set_u64(&mut self, value: u64);
@ -228,7 +237,7 @@ pub unsafe extern "C" fn object_bytearray_get(
set: fn(*mut c_void, QByteArray),
) {
let data = (&*ptr).get_bytearray();
set(p, QByteArray::from(&data));
set(p, data.into());
}
#[no_mangle]
@ -254,7 +263,7 @@ pub unsafe extern "C" fn object_optional_bytearray_get(
) {
let data = (&*ptr).get_optional_bytearray();
if let Some(data) = data {
set(p, QByteArray::from(&data));
set(p, data.into());
}
}
@ -275,7 +284,7 @@ pub unsafe extern "C" fn object_optional_string_get(
) {
let data = (&*ptr).get_optional_string();
if let Some(data) = data {
set(p, QString::from(&data));
set(p, data.into());
}
}
@ -295,7 +304,7 @@ pub unsafe extern "C" fn object_string_get(
set: fn(*mut c_void, QString),
) {
let data = (&*ptr).get_string();
set(p, QString::from(&data));
set(p, data.into());
}
#[no_mangle]

View File

@ -41,8 +41,8 @@ impl InnerObjectTrait for InnerObject {
fn emit(&self) -> &InnerObjectEmitter {
&self.emit
}
fn get_description(&self) -> String {
self.description.clone()
fn get_description(&self) -> &str {
&self.description
}
fn set_description(&mut self, value: String) {
self.description = value;

View File

@ -29,6 +29,15 @@ impl QStringIn {
}
}
impl<'a> From<&'a str> for QString {
fn from(string: &'a str) -> QString {
QString {
len: string.len() as c_int,
data: string.as_ptr(),
}
}
}
impl<'a> From<&'a String> for QString {
fn from(string: &'a String) -> QString {
QString {
@ -121,7 +130,7 @@ impl InnerObjectEmitter {
pub trait InnerObjectTrait {
fn create(emit: InnerObjectEmitter) -> Self;
fn emit(&self) -> &InnerObjectEmitter;
fn get_description(&self) -> String;
fn get_description(&self) -> &str;
fn set_description(&mut self, value: String);
}
@ -150,7 +159,7 @@ pub unsafe extern "C" fn inner_object_description_get(
set: fn(*mut c_void, QString),
) {
let data = (&*ptr).get_description();
set(p, QString::from(&data));
set(p, data.into());
}
#[no_mangle]

View File

@ -37,8 +37,8 @@ impl PersonsTrait for Persons {
fn row(&self, item: usize) -> usize {
item
}
fn user_name(&self, item: usize) -> String {
self.list[item].user_name.clone()
fn user_name(&self, item: usize) -> &str {
&self.list[item].user_name
}
fn set_user_name(&mut self, item: usize, v: String) -> bool {
self.list[item].user_name = v;

View File

@ -55,6 +55,15 @@ impl QStringIn {
}
}
impl<'a> From<&'a str> for QString {
fn from(string: &'a str) -> QString {
QString {
len: string.len() as c_int,
data: string.as_ptr(),
}
}
}
impl<'a> From<&'a String> for QString {
fn from(string: &'a String) -> QString {
QString {
@ -146,7 +155,7 @@ pub trait PersonsTrait {
fn index(&self, item: Option<usize>, row: usize) -> usize;
fn parent(&self, item: usize) -> Option<usize>;
fn row(&self, item: usize) -> usize;
fn user_name(&self, item: usize) -> String;
fn user_name(&self, item: usize) -> &str;
fn set_user_name(&mut self, item: usize, String) -> bool;
}
@ -264,7 +273,7 @@ pub unsafe extern "C" fn persons_data_user_name(
set: fn(*mut c_void, QString),
) {
let data = (&*ptr).user_name(item);
set(d, QString::from(&data));
set(d, (data).into());
}
#[no_mangle]