Warning, /sdk/rust-qt-binding-generator/src/cpp.rs is written in an unsupported language. File is not indexed.

0001 //! `cpp` is the module that generates the cpp code for the bindings
0002 
0003 use configuration::*;
0004 use configuration_private::*;
0005 use std::io::{Result, Write};
0006 use util::{snake_case, write_if_different};
0007 
0008 fn property_type(p: &ItemProperty) -> String {
0009     if p.optional && !p.item_property_type.is_complex() {
0010         return "QVariant".into();
0011     }
0012     p.type_name().to_string()
0013 }
0014 
0015 fn upper_initial(name: &str) -> String {
0016     format!("{}{}", &name[..1].to_uppercase(), &name[1..])
0017 }
0018 
0019 fn lower_initial(name: &str) -> String {
0020     format!("{}{}", &name[..1].to_lowercase(), &name[1..])
0021 }
0022 
0023 fn write_property(name: &str) -> String {
0024     format!("WRITE set{} ", upper_initial(name))
0025 }
0026 
0027 fn base_type(o: &Object) -> &str {
0028     if o.object_type != ObjectType::Object {
0029         return "QAbstractItemModel";
0030     }
0031     "QObject"
0032 }
0033 
0034 fn model_is_writable(o: &Object) -> bool {
0035     let mut write = false;
0036     for p in o.item_properties.values() {
0037         write |= p.write;
0038     }
0039     write
0040 }
0041 
0042 fn write_header_item_model(h: &mut Vec<u8>, o: &Object) -> Result<()> {
0043     writeln!(
0044         h,
0045         "
0046     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
0047     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
0048     QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
0049     QModelIndex parent(const QModelIndex &index) const override;
0050     bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;
0051     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
0052     bool canFetchMore(const QModelIndex &parent) const override;
0053     void fetchMore(const QModelIndex &parent) override;
0054     Qt::ItemFlags flags(const QModelIndex &index) const override;
0055     void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override;
0056     int role(const char* name) const;
0057     QHash<int, QByteArray> roleNames() const override;
0058     QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
0059     bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) override;
0060     Q_INVOKABLE bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
0061     Q_INVOKABLE bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;"
0062     )?;
0063     if model_is_writable(o) {
0064         writeln!(
0065             h,
0066             "    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;"
0067         )?;
0068     }
0069     for (name, ip) in &o.item_properties {
0070         let r = property_type(ip);
0071         let rw = if r == "QVariant" || ip.item_property_type.is_complex() {
0072             format!("const {}&", r)
0073         } else {
0074             r.clone()
0075         };
0076         if o.object_type == ObjectType::List {
0077             writeln!(h, "    Q_INVOKABLE {} {}(int row) const;", r, name)?;
0078             if ip.write {
0079                 writeln!(
0080                     h,
0081                     "    Q_INVOKABLE bool set{}(int row, {} value);",
0082                     upper_initial(name),
0083                     rw
0084                 )?;
0085             }
0086         } else {
0087             writeln!(
0088                 h,
0089                 "    Q_INVOKABLE {} {}(const QModelIndex& index) const;",
0090                 r, name
0091             )?;
0092             if ip.write {
0093                 writeln!(
0094                     h,
0095                     "    Q_INVOKABLE bool set{}(const QModelIndex& index, {} value);",
0096                     upper_initial(name),
0097                     rw
0098                 )?;
0099             }
0100         }
0101     }
0102     writeln!(
0103         h,
0104         "
0105 Q_SIGNALS:
0106     // new data is ready to be made available to the model with fetchMore()
0107     void newDataReady(const QModelIndex &parent) const;
0108 private:
0109     QHash<QPair<int,Qt::ItemDataRole>, QVariant> m_headerData;
0110     void initHeaderData();
0111     void updatePersistentIndexes();"
0112     )?;
0113     Ok(())
0114 }
0115 
0116 fn write_header_object(h: &mut Vec<u8>, o: &Object, conf: &Config) -> Result<()> {
0117     writeln!(
0118         h,
0119         "
0120 class {} : public {}
0121 {{
0122     Q_OBJECT",
0123         o.name,
0124         base_type(o)
0125     )?;
0126     for object in conf.objects.values() {
0127         if object.contains_object() && o.name != object.name {
0128             writeln!(h, "    friend class {};", object.name)?;
0129         }
0130     }
0131     writeln!(
0132         h,
0133         "public:
0134     class Private;
0135 private:"
0136     )?;
0137     for (name, p) in &o.properties {
0138         if p.is_object() {
0139             writeln!(h, "    {}* const m_{};", p.type_name(), name)?;
0140         }
0141     }
0142     writeln!(
0143         h,
0144         "    Private * m_d;
0145     bool m_ownsPrivate;"
0146     )?;
0147     for (name, p) in &o.properties {
0148         let mut t = if p.optional && !p.is_complex() {
0149             "QVariant"
0150         } else {
0151             p.type_name()
0152         }
0153         .to_string();
0154         if p.is_object() {
0155             t.push('*');
0156         }
0157         writeln!(
0158             h,
0159             "    Q_PROPERTY({0} {1} READ {1} {2}NOTIFY {1}Changed FINAL)",
0160             t,
0161             name,
0162             if p.write {
0163                 write_property(name)
0164             } else {
0165                 String::new()
0166             }
0167         )?;
0168     }
0169     writeln!(
0170         h,
0171         "    explicit {}(bool owned, QObject *parent);
0172 public:
0173     explicit {0}(QObject *parent = nullptr);
0174     ~{0}();",
0175         o.name
0176     )?;
0177     for (name, p) in &o.properties {
0178         if p.is_object() {
0179             writeln!(h, "    const {}* {}() const;", p.type_name(), name)?;
0180             writeln!(h, "    {}* {}();", p.type_name(), name)?;
0181         } else {
0182             let (t, t2) = if p.optional && !p.is_complex() {
0183                 ("QVariant", "const QVariant&")
0184             } else {
0185                 (p.type_name(), p.property_type.cpp_set_type())
0186             };
0187             writeln!(h, "    {} {}() const;", t, name)?;
0188             if p.write {
0189                 writeln!(h, "    void set{}({} v);", upper_initial(name), t2)?;
0190             }
0191         }
0192     }
0193     for (name, f) in &o.functions {
0194         write!(h, "    Q_INVOKABLE {} {}(", f.return_type.name(), name)?;
0195         for (i, a) in f.arguments.iter().enumerate() {
0196             if i != 0 {
0197                 write!(h, ", ")?;
0198             }
0199             write!(h, "{} {}", a.argument_type.cpp_set_type(), a.name)?;
0200         }
0201         writeln!(h, "){};", if f.mutable { "" } else { " const" })?;
0202     }
0203     if base_type(o) == "QAbstractItemModel" {
0204         write_header_item_model(h, o)?;
0205     }
0206     writeln!(h, "Q_SIGNALS:")?;
0207     for name in o.properties.keys() {
0208         writeln!(h, "    void {}Changed();", name)?;
0209     }
0210     writeln!(h, "}};")?;
0211     Ok(())
0212 }
0213 
0214 fn is_column_write(o: &Object, col: usize) -> bool {
0215     o.item_properties
0216         .values()
0217         .any(|ip| ip.write && (col == 0 || (ip.roles.len() > col && !ip.roles[col].is_empty())))
0218 }
0219 
0220 fn write_function_c_decl(
0221     w: &mut Vec<u8>,
0222     (name, f): (&String, &Function),
0223     lcname: &str,
0224     o: &Object,
0225 ) -> Result<()> {
0226     let lc = snake_case(name);
0227     write!(w, "    ")?;
0228     if f.return_type.is_complex() {
0229         write!(w, "void")?;
0230     } else {
0231         write!(w, "{}", f.type_name())?;
0232     }
0233     let name = format!("{}_{}", lcname, lc);
0234     write!(
0235         w,
0236         " {}({}{}::Private*",
0237         name,
0238         if f.mutable { "" } else { "const " },
0239         o.name
0240     )?;
0241 
0242     // write all the input arguments, for QString and QByteArray, write
0243     // pointers to their content and the length
0244     for a in &f.arguments {
0245         if a.type_name() == "QString" {
0246             write!(w, ", const ushort*, int")?;
0247         } else if a.type_name() == "QByteArray" {
0248             write!(w, ", const char*, int")?;
0249         } else {
0250             write!(w, ", {}", a.type_name())?;
0251         }
0252     }
0253     // If the return type is QString or QByteArray, append a pointer to the
0254     // variable that will be set to the argument list. Also add a setter
0255     // function.
0256     if f.return_type.name() == "QString" {
0257         write!(w, ", QString*, qstring_set")?;
0258     } else if f.return_type.name() == "QByteArray" {
0259         write!(w, ", QByteArray*, qbytearray_set")?;
0260     }
0261     writeln!(w, ");")?;
0262     Ok(())
0263 }
0264 
0265 fn write_object_c_decl(w: &mut Vec<u8>, o: &Object, conf: &Config) -> Result<()> {
0266     let lcname = snake_case(&o.name);
0267     write!(w, "    {}::Private* {}_new(", o.name, lcname)?;
0268     constructor_args_decl(w, o, conf)?;
0269     writeln!(w, ");")?;
0270     writeln!(w, "    void {}_free({}::Private*);", lcname, o.name)?;
0271     for (name, p) in &o.properties {
0272         let base = format!("{}_{}", lcname, snake_case(name));
0273         if p.is_object() {
0274             writeln!(
0275                 w,
0276                 "    {}::Private* {}_get(const {}::Private*);",
0277                 p.type_name(),
0278                 base,
0279                 o.name
0280             )?;
0281         } else if p.is_complex() {
0282             writeln!(
0283                 w,
0284                 "    void {}_get(const {}::Private*, {});",
0285                 base,
0286                 o.name,
0287                 p.c_get_type()
0288             )?;
0289         } else if p.optional {
0290             writeln!(
0291                 w,
0292                 "    option_{} {}_get(const {}::Private*);",
0293                 p.type_name(),
0294                 base,
0295                 o.name
0296             )?;
0297         } else {
0298             writeln!(
0299                 w,
0300                 "    {} {}_get(const {}::Private*);",
0301                 p.type_name(),
0302                 base,
0303                 o.name
0304             )?;
0305         }
0306         if p.write {
0307             let mut t = p.property_type.c_set_type();
0308             if t == "qstring_t" {
0309                 t = "const ushort *str, int len";
0310             } else if t == "qbytearray_t" {
0311                 t = "const char* bytes, int len";
0312             }
0313             writeln!(w, "    void {}_set({}::Private*, {});", base, o.name, t)?;
0314             if p.optional {
0315                 writeln!(w, "    void {}_set_none({}::Private*);", base, o.name)?;
0316             }
0317         }
0318     }
0319     for f in &o.functions {
0320         write_function_c_decl(w, f, &lcname, o)?;
0321     }
0322     Ok(())
0323 }
0324 
0325 fn initialize_members_zero(w: &mut Vec<u8>, o: &Object) -> Result<()> {
0326     for (name, p) in &o.properties {
0327         if p.is_object() {
0328             writeln!(w, "    m_{}(new {}(false, this)),", name, p.type_name())?;
0329         }
0330     }
0331     Ok(())
0332 }
0333 
0334 fn initialize_members(w: &mut Vec<u8>, prefix: &str, o: &Object, conf: &Config) -> Result<()> {
0335     for (name, p) in &o.properties {
0336         if let Type::Object(object) = &p.property_type {
0337             writeln!(
0338                 w,
0339                 "    {}m_{}->m_d = {}_{}_get({0}m_d);",
0340                 prefix,
0341                 name,
0342                 snake_case(&o.name),
0343                 snake_case(name)
0344             )?;
0345             initialize_members(w, &format!("m_{}->", name), object, conf)?;
0346         }
0347     }
0348     Ok(())
0349 }
0350 
0351 fn connect(w: &mut Vec<u8>, d: &str, o: &Object, conf: &Config) -> Result<()> {
0352     for (name, p) in &o.properties {
0353         if let Type::Object(object) = &p.property_type {
0354             connect(w, &format!("{}->m_{}", d, name), object, conf)?;
0355         }
0356     }
0357     if o.object_type != ObjectType::Object {
0358         writeln!(
0359             w,
0360             "    connect({}, &{1}::newDataReady, {0}, [this](const QModelIndex& i) {{
0361         {0}->fetchMore(i);
0362     }}, Qt::QueuedConnection);",
0363             d, o.name
0364         )?;
0365     }
0366     Ok(())
0367 }
0368 
0369 fn write_cpp_object_properties(w: &mut Vec<u8>, o: &Object, lcname: &str) -> Result<()> {
0370     for (name, p) in &o.properties {
0371         let base = format!("{}_{}", lcname, snake_case(name));
0372         if p.is_object() {
0373             writeln!(
0374                 w,
0375                 "const {}* {}::{}() const
0376 {{
0377     return m_{2};
0378 }}
0379 {0}* {1}::{2}()
0380 {{
0381     return m_{2};
0382 }}",
0383                 p.type_name(),
0384                 o.name,
0385                 name
0386             )?;
0387         } else if p.is_complex() {
0388             writeln!(
0389                 w,
0390                 "{} {}::{}() const
0391 {{
0392     {0} v;
0393     {3}_get(m_d, &v, set_{4});
0394     return v;
0395 }}",
0396                 p.type_name(),
0397                 o.name,
0398                 name,
0399                 base,
0400                 p.type_name().to_lowercase()
0401             )?;
0402         } else if p.optional {
0403             writeln!(
0404                 w,
0405                 "QVariant {}::{}() const
0406 {{
0407     QVariant v;
0408     auto r = {2}_get(m_d);
0409     if (r.some) {{
0410         v.setValue(r.value);
0411     }}
0412     return r;
0413 }}",
0414                 o.name, name, base
0415             )?;
0416         } else {
0417             writeln!(
0418                 w,
0419                 "{} {}::{}() const
0420 {{
0421     return {}_get(m_d);
0422 }}",
0423                 p.type_name(),
0424                 o.name,
0425                 name,
0426                 base
0427             )?;
0428         }
0429         if p.write {
0430             let t = if p.optional && !p.is_complex() {
0431                 "const QVariant&"
0432             } else {
0433                 p.property_type.cpp_set_type()
0434             };
0435             writeln!(w, "void {}::set{}({} v) {{", o.name, upper_initial(name), t)?;
0436             if p.optional {
0437                 if p.is_complex() {
0438                     writeln!(w, "    if (v.isNull()) {{")?;
0439                 } else {
0440                     writeln!(
0441                         w,
0442                         "    if (v.isNull() || !v.canConvert<{}>()) {{",
0443                         p.type_name()
0444                     )?;
0445                 }
0446                 writeln!(w, "        {}_set_none(m_d);", base)?;
0447                 writeln!(w, "    }} else {{")?;
0448                 if p.type_name() == "QString" {
0449                     writeln!(
0450                         w,
0451                         "    {}_set(m_d, reinterpret_cast<const ushort*>(v.data()), v.size());",
0452                         base
0453                     )?;
0454                 } else if p.type_name() == "QByteArray" {
0455                     writeln!(w, "    {}_set(m_d, v.data(), v.size());", base)?;
0456                 } else if p.optional {
0457                     writeln!(
0458                         w,
0459                         "        {}_set(m_d, v.value<{}>());",
0460                         base,
0461                         p.type_name()
0462                     )?;
0463                 } else {
0464                     writeln!(w, "        {}_set(m_d, v);", base)?;
0465                 }
0466                 writeln!(w, "    }}")?;
0467             } else if p.type_name() == "QString" {
0468                 writeln!(
0469                     w,
0470                     "    {}_set(m_d, reinterpret_cast<const ushort*>(v.data()), v.size());",
0471                     base
0472                 )?;
0473             } else if p.type_name() == "QByteArray" {
0474                 writeln!(w, "    {}_set(m_d, v.data(), v.size());", base)?;
0475             } else {
0476                 writeln!(w, "    {}_set(m_d, v);", base)?;
0477             }
0478             writeln!(w, "}}")?;
0479         }
0480     }
0481     Ok(())
0482 }
0483 
0484 fn write_cpp_object(w: &mut Vec<u8>, o: &Object, conf: &Config) -> Result<()> {
0485     let lcname = snake_case(&o.name);
0486     writeln!(
0487         w,
0488         "{}::{0}(bool /*owned*/, QObject *parent):
0489     {}(parent),",
0490         o.name,
0491         base_type(o)
0492     )?;
0493     initialize_members_zero(w, o)?;
0494     writeln!(
0495         w,
0496         "    m_d(nullptr),
0497     m_ownsPrivate(false)
0498 {{"
0499     )?;
0500     if o.object_type != ObjectType::Object {
0501         writeln!(w, "    initHeaderData();")?;
0502     }
0503     writeln!(
0504         w,
0505         "}}
0506 
0507 {}::{0}(QObject *parent):
0508     {}(parent),",
0509         o.name,
0510         base_type(o)
0511     )?;
0512     initialize_members_zero(w, o)?;
0513     write!(w, "    m_d({}_new(this", lcname)?;
0514     constructor_args(w, "", o, conf)?;
0515     writeln!(
0516         w,
0517         ")),
0518     m_ownsPrivate(true)
0519 {{"
0520     )?;
0521     initialize_members(w, "", o, conf)?;
0522     connect(w, "this", o, conf)?;
0523     if o.object_type != ObjectType::Object {
0524         writeln!(w, "    initHeaderData();")?;
0525     }
0526     writeln!(
0527         w,
0528         "}}
0529 
0530 {}::~{0}() {{
0531     if (m_ownsPrivate) {{
0532         {1}_free(m_d);
0533     }}
0534 }}",
0535         o.name, lcname
0536     )?;
0537     if o.object_type != ObjectType::Object {
0538         writeln!(w, "void {}::initHeaderData() {{", o.name)?;
0539         for col in 0..o.column_count() {
0540             for (name, ip) in &o.item_properties {
0541                 let empty = Vec::new();
0542                 let roles = ip.roles.get(col).unwrap_or(&empty);
0543                 if roles.contains(&"display".to_string()) {
0544                     writeln!(
0545                         w,
0546                         "    m_headerData.insert(qMakePair({}, Qt::DisplayRole), QVariant(\"{}\"));",
0547                         col,
0548                         name
0549                     )?;
0550                 }
0551             }
0552         }
0553         writeln!(w, "}}")?;
0554     }
0555 
0556     write_cpp_object_properties(w, o, &lcname)?;
0557 
0558     for (name, f) in &o.functions {
0559         let base = format!("{}_{}", lcname, snake_case(name));
0560         write!(w, "{} {}::{}(", f.type_name(), o.name, name)?;
0561         for (i, a) in f.arguments.iter().enumerate() {
0562             write!(
0563                 w,
0564                 "{} {}{}",
0565                 a.argument_type.cpp_set_type(),
0566                 a.name,
0567                 if i + 1 < f.arguments.len() { ", " } else { "" }
0568             )?;
0569         }
0570         writeln!(w, "){}\n{{", if f.mutable { "" } else { " const" })?;
0571         let mut arg_list = String::new();
0572         for a in &f.arguments {
0573             if a.type_name() == "QString" {
0574                 arg_list.push_str(&format!(", {}.utf16(), {0}.size()", a.name));
0575             } else if a.type_name() == "QByteArray" {
0576                 arg_list.push_str(&format!(", {}.data(), {0}.size()", a.name));
0577             } else {
0578                 arg_list.push_str(&format!(", {}", a.name));
0579             }
0580         }
0581         if f.return_type.name() == "QString" {
0582             writeln!(
0583                 w,
0584                 "    {} s;
0585     {}(m_d{}, &s, set_qstring);
0586     return s;",
0587                 f.type_name(),
0588                 base,
0589                 arg_list
0590             )?;
0591         } else if f.return_type.name() == "QByteArray" {
0592             writeln!(
0593                 w,
0594                 "    {} s;
0595     {}(m_d{}, &s, set_qbytearray);
0596     return s;",
0597                 f.type_name(),
0598                 base,
0599                 arg_list
0600             )?;
0601         } else {
0602             writeln!(w, "    return {}(m_d{});", base, arg_list)?;
0603         }
0604         writeln!(w, "}}")?;
0605     }
0606     Ok(())
0607 }
0608 
0609 fn role_name(role: &str) -> String {
0610     match role {
0611         "display" => "DisplayRole".into(),
0612         "decoration" => "DecorationRole".into(),
0613         "edit" => "EditRole".into(),
0614         "toolTip" => "ToolTipRole".into(),
0615         "statustip" => "StatusTipRole".into(),
0616         "whatsthis" => "WhatsThisRole".into(),
0617         _ => panic!("Unknown role {}", role),
0618     }
0619 }
0620 
0621 fn write_model_getter_setter(
0622     w: &mut Vec<u8>,
0623     index: &str,
0624     name: &str,
0625     ip: &ItemProperty,
0626     o: &Object,
0627 ) -> Result<()> {
0628     let lcname = snake_case(&o.name);
0629     let mut idx = index;
0630 
0631     // getter
0632     let mut r = property_type(ip);
0633     if o.object_type == ObjectType::List {
0634         idx = ", row";
0635         writeln!(w, "{} {}::{}(int row) const\n{{", r, o.name, name)?;
0636     } else {
0637         writeln!(
0638             w,
0639             "{} {}::{}(const QModelIndex& index) const\n{{",
0640             r, o.name, name
0641         )?;
0642     }
0643     if ip.type_name() == "QString" {
0644         writeln!(w, "    QString s;")?;
0645         writeln!(
0646             w,
0647             "    {}_data_{}(m_d{}, &s, set_{});",
0648             lcname,
0649             snake_case(name),
0650             idx,
0651             ip.type_name().to_lowercase()
0652         )?;
0653         writeln!(w, "    return s;")?;
0654     } else if ip.type_name() == "QByteArray" {
0655         writeln!(w, "    QByteArray b;")?;
0656         writeln!(
0657             w,
0658             "    {}_data_{}(m_d{}, &b, set_{});",
0659             lcname,
0660             snake_case(name),
0661             idx,
0662             ip.type_name().to_lowercase()
0663         )?;
0664         writeln!(w, "    return b;")?;
0665     } else if ip.optional {
0666         writeln!(w, "    QVariant v;")?;
0667         writeln!(
0668             w,
0669             "    v = {}_data_{}(m_d{});",
0670             lcname,
0671             snake_case(name),
0672             idx
0673         )?;
0674         writeln!(w, "    return v;")?;
0675     } else {
0676         writeln!(
0677             w,
0678             "    return {}_data_{}(m_d{});",
0679             lcname,
0680             snake_case(name),
0681             idx
0682         )?;
0683     }
0684     writeln!(w, "}}\n")?;
0685     if !ip.write {
0686         return Ok(());
0687     }
0688 
0689     //setter
0690     if r == "QVariant" || ip.is_complex() {
0691         r = format!("const {}&", r);
0692     }
0693     if o.object_type == ObjectType::List {
0694         idx = ", row";
0695         writeln!(
0696             w,
0697             "bool {}::set{}(int row, {} value)\n{{",
0698             o.name,
0699             upper_initial(name),
0700             r
0701         )?;
0702     } else {
0703         writeln!(
0704             w,
0705             "bool {}::set{}(const QModelIndex& index, {} value)\n{{",
0706             o.name,
0707             upper_initial(name),
0708             r
0709         )?;
0710     }
0711     writeln!(w, "    bool set = false;")?;
0712     if ip.optional {
0713         let mut test = "value.isNull()".to_string();
0714         if !ip.is_complex() {
0715             test += " || !value.isValid()";
0716         }
0717         writeln!(w, "    if ({}) {{", test)?;
0718         writeln!(
0719             w,
0720             "        set = {}_set_data_{}_none(m_d{});",
0721             lcname,
0722             snake_case(name),
0723             idx
0724         )?;
0725         writeln!(w, "    }} else {{")?;
0726     }
0727     if ip.optional && !ip.is_complex() {
0728         writeln!(
0729             w,
0730             "    if (!value.canConvert(qMetaTypeId<{}>())) {{
0731         return false;
0732     }}",
0733             ip.type_name()
0734         )?;
0735         writeln!(
0736             w,
0737             "    set = {}_set_data_{}(m_d{}, value.value<{}>());",
0738             lcname,
0739             snake_case(name),
0740             idx,
0741             ip.type_name()
0742         )?;
0743     } else {
0744         let mut val = "value";
0745         if ip.is_complex() {
0746             if ip.type_name() == "QString" {
0747                 val = "value.utf16(), value.length()";
0748             } else {
0749                 val = "value.data(), value.length()";
0750             }
0751         }
0752         writeln!(
0753             w,
0754             "    set = {}_set_data_{}(m_d{}, {});",
0755             lcname,
0756             snake_case(name),
0757             idx,
0758             val
0759         )?;
0760     }
0761     if ip.optional {
0762         writeln!(w, "    }}")?;
0763     }
0764     if o.object_type == ObjectType::List {
0765         writeln!(
0766             w,
0767             "    if (set) {{
0768         QModelIndex index = createIndex(row, 0, row);
0769         Q_EMIT dataChanged(index, index);
0770     }}
0771     return set;
0772 }}
0773 "
0774         )?;
0775     } else {
0776         writeln!(
0777             w,
0778             "    if (set) {{
0779         Q_EMIT dataChanged(index, index);
0780     }}
0781     return set;
0782 }}
0783 "
0784         )?;
0785     }
0786     Ok(())
0787 }
0788 
0789 fn write_cpp_model(w: &mut Vec<u8>, o: &Object) -> Result<()> {
0790     let lcname = snake_case(&o.name);
0791     let (index_decl, index) = if o.object_type == ObjectType::Tree {
0792         (", quintptr", ", index.internalId()")
0793     } else {
0794         (", int", ", index.row()")
0795     };
0796     writeln!(w, "extern \"C\" {{")?;
0797 
0798     for (name, ip) in &o.item_properties {
0799         if ip.is_complex() {
0800             writeln!(
0801                 w,
0802                 "    void {}_data_{}(const {}::Private*{}, {});",
0803                 lcname,
0804                 snake_case(name),
0805                 o.name,
0806                 index_decl,
0807                 ip.c_get_type()
0808             )?;
0809         } else {
0810             writeln!(
0811                 w,
0812                 "    {} {}_data_{}(const {}::Private*{});",
0813                 ip.cpp_set_type(),
0814                 lcname,
0815                 snake_case(name),
0816                 o.name,
0817                 index_decl
0818             )?;
0819         }
0820         if ip.write {
0821             let a = format!("    bool {}_set_data_{}", lcname, snake_case(name));
0822             let b = format!("({}::Private*{}", o.name, index_decl);
0823             if ip.type_name() == "QString" {
0824                 writeln!(w, "{}{}, const ushort* s, int len);", a, b)?;
0825             } else if ip.type_name() == "QByteArray" {
0826                 writeln!(w, "{}{}, const char* s, int len);", a, b)?;
0827             } else {
0828                 writeln!(w, "{}{}, {});", a, b, ip.c_set_type())?;
0829             }
0830             if ip.optional {
0831                 writeln!(w, "{}_none{});", a, b)?;
0832             }
0833         }
0834     }
0835     writeln!(
0836         w,
0837         "    void {}_sort({}::Private*, unsigned char column, Qt::SortOrder order = Qt::AscendingOrder);",
0838         lcname,
0839         o.name
0840     )?;
0841     if o.object_type == ObjectType::List {
0842         writeln!(
0843             w,
0844             "
0845     int {1}_row_count(const {0}::Private*);
0846     bool {1}_insert_rows({0}::Private*, int, int);
0847     bool {1}_remove_rows({0}::Private*, int, int);
0848     bool {1}_can_fetch_more(const {0}::Private*);
0849     void {1}_fetch_more({0}::Private*);
0850 }}
0851 int {0}::columnCount(const QModelIndex &parent) const
0852 {{
0853     return (parent.isValid()) ? 0 : {2};
0854 }}
0855 
0856 bool {0}::hasChildren(const QModelIndex &parent) const
0857 {{
0858     return rowCount(parent) > 0;
0859 }}
0860 
0861 int {0}::rowCount(const QModelIndex &parent) const
0862 {{
0863     return (parent.isValid()) ? 0 : {1}_row_count(m_d);
0864 }}
0865 
0866 bool {0}::insertRows(int row, int count, const QModelIndex &)
0867 {{
0868     return {1}_insert_rows(m_d, row, count);
0869 }}
0870 
0871 bool {0}::removeRows(int row, int count, const QModelIndex &)
0872 {{
0873     return {1}_remove_rows(m_d, row, count);
0874 }}
0875 
0876 QModelIndex {0}::index(int row, int column, const QModelIndex &parent) const
0877 {{
0878     if (!parent.isValid() && row >= 0 && row < rowCount(parent) && column >= 0 && column < {2}) {{
0879         return createIndex(row, column, (quintptr)row);
0880     }}
0881     return QModelIndex();
0882 }}
0883 
0884 QModelIndex {0}::parent(const QModelIndex &) const
0885 {{
0886     return QModelIndex();
0887 }}
0888 
0889 bool {0}::canFetchMore(const QModelIndex &parent) const
0890 {{
0891     return (parent.isValid()) ? 0 : {1}_can_fetch_more(m_d);
0892 }}
0893 
0894 void {0}::fetchMore(const QModelIndex &parent)
0895 {{
0896     if (!parent.isValid()) {{
0897         {1}_fetch_more(m_d);
0898     }}
0899 }}
0900 void {0}::updatePersistentIndexes() {{}}",
0901             o.name,
0902             lcname,
0903             o.column_count()
0904         )?;
0905     } else {
0906         writeln!(
0907             w,
0908             "
0909     int {1}_row_count(const {0}::Private*, option_quintptr);
0910     bool {1}_can_fetch_more(const {0}::Private*, option_quintptr);
0911     void {1}_fetch_more({0}::Private*, option_quintptr);
0912     quintptr {1}_index(const {0}::Private*, option_quintptr, int);
0913     qmodelindex_t {1}_parent(const {0}::Private*, quintptr);
0914     int {1}_row(const {0}::Private*, quintptr);
0915     option_quintptr {1}_check_row(const {0}::Private*, quintptr, int);
0916 }}
0917 int {0}::columnCount(const QModelIndex &) const
0918 {{
0919     return {2};
0920 }}
0921 
0922 bool {0}::hasChildren(const QModelIndex &parent) const
0923 {{
0924     return rowCount(parent) > 0;
0925 }}
0926 
0927 int {0}::rowCount(const QModelIndex &parent) const
0928 {{
0929     if (parent.isValid() && parent.column() != 0) {{
0930         return 0;
0931     }}
0932     const option_quintptr rust_parent = {{
0933         parent.internalId(),
0934         parent.isValid()
0935     }};
0936     return {1}_row_count(m_d, rust_parent);
0937 }}
0938 
0939 bool {0}::insertRows(int, int, const QModelIndex &)
0940 {{
0941     return false; // not supported yet
0942 }}
0943 
0944 bool {0}::removeRows(int, int, const QModelIndex &)
0945 {{
0946     return false; // not supported yet
0947 }}
0948 
0949 QModelIndex {0}::index(int row, int column, const QModelIndex &parent) const
0950 {{
0951     if (row < 0 || column < 0 || column >= {2}) {{
0952         return QModelIndex();
0953     }}
0954     if (parent.isValid() && parent.column() != 0) {{
0955         return QModelIndex();
0956     }}
0957     if (row >= rowCount(parent)) {{
0958         return QModelIndex();
0959     }}
0960     const option_quintptr rust_parent = {{
0961         parent.internalId(),
0962         parent.isValid()
0963     }};
0964     const quintptr id = {1}_index(m_d, rust_parent, row);
0965     return createIndex(row, column, id);
0966 }}
0967 
0968 QModelIndex {0}::parent(const QModelIndex &index) const
0969 {{
0970     if (!index.isValid()) {{
0971         return QModelIndex();
0972     }}
0973     const qmodelindex_t parent = {1}_parent(m_d, index.internalId());
0974     return parent.row >= 0 ?createIndex(parent.row, 0, parent.id) :QModelIndex();
0975 }}
0976 
0977 bool {0}::canFetchMore(const QModelIndex &parent) const
0978 {{
0979     if (parent.isValid() && parent.column() != 0) {{
0980         return false;
0981     }}
0982     const option_quintptr rust_parent = {{
0983         parent.internalId(),
0984         parent.isValid()
0985     }};
0986     return {1}_can_fetch_more(m_d, rust_parent);
0987 }}
0988 
0989 void {0}::fetchMore(const QModelIndex &parent)
0990 {{
0991     const option_quintptr rust_parent = {{
0992         parent.internalId(),
0993         parent.isValid()
0994     }};
0995     {1}_fetch_more(m_d, rust_parent);
0996 }}
0997 void {0}::updatePersistentIndexes() {{
0998     const auto from = persistentIndexList();
0999     auto to = from;
1000     auto len = to.size();
1001     for (int i = 0; i < len; ++i) {{
1002         auto index = to.at(i);
1003         auto row = {1}_check_row(m_d, index.internalId(), index.row());
1004         if (row.some) {{
1005             to[i] = createIndex(row.value, index.column(), index.internalId());
1006         }} else {{
1007             to[i] = QModelIndex();
1008         }}
1009     }}
1010     changePersistentIndexList(from, to);
1011 }}",
1012             o.name,
1013             lcname,
1014             o.column_count()
1015         )?;
1016     }
1017     writeln!(
1018         w,
1019         "
1020 void {0}::sort(int column, Qt::SortOrder order)
1021 {{
1022     {1}_sort(m_d, column, order);
1023 }}
1024 Qt::ItemFlags {0}::flags(const QModelIndex &i) const
1025 {{
1026     auto flags = QAbstractItemModel::flags(i);",
1027         o.name, lcname
1028     )?;
1029     for col in 0..o.column_count() {
1030         if is_column_write(o, col) {
1031             writeln!(w, "    if (i.column() == {}) {{", col)?;
1032             writeln!(w, "        flags |= Qt::ItemIsEditable;\n    }}")?;
1033         }
1034     }
1035     writeln!(w, "    return flags;\n}}\n")?;
1036     for ip in &o.item_properties {
1037         write_model_getter_setter(w, index, ip.0, ip.1, o)?;
1038     }
1039     writeln!(
1040         w,
1041         "QVariant {}::data(const QModelIndex &index, int role) const
1042 {{
1043     Q_ASSERT(rowCount(index.parent()) > index.row());
1044     switch (index.column()) {{",
1045         o.name
1046     )?;
1047 
1048     for col in 0..o.column_count() {
1049         writeln!(w, "    case {}:", col)?;
1050         writeln!(w, "        switch (role) {{")?;
1051         for (i, (name, ip)) in o.item_properties.iter().enumerate() {
1052             let empty = Vec::new();
1053             let roles = ip.roles.get(col).unwrap_or(&empty);
1054             if col > 0 && roles.is_empty() {
1055                 continue;
1056             }
1057             for role in roles {
1058                 writeln!(w, "        case Qt::{}:", role_name(role))?;
1059             }
1060             writeln!(w, "        case Qt::UserRole + {}:", i)?;
1061             let ii = if o.object_type == ObjectType::List {
1062                 ".row()"
1063             } else {
1064                 ""
1065             };
1066             if ip.optional && !ip.is_complex() {
1067                 writeln!(w, "            return {}(index{});", name, ii)?;
1068             } else if ip.optional {
1069                 writeln!(
1070                     w,
1071                     "            return cleanNullQVariant(QVariant::fromValue({}(index{})));",
1072                     name, ii
1073                 )?;
1074             } else {
1075                 writeln!(
1076                     w,
1077                     "            return QVariant::fromValue({}(index{}));",
1078                     name, ii
1079                 )?;
1080             }
1081         }
1082         writeln!(w, "        }}\n        break;")?;
1083     }
1084     writeln!(
1085         w,
1086         "    }}
1087     return QVariant();
1088 }}
1089 
1090 int {}::role(const char* name) const {{
1091     auto names = roleNames();
1092     auto i = names.constBegin();
1093     while (i != names.constEnd()) {{
1094         if (i.value() == name) {{
1095             return i.key();
1096         }}
1097         ++i;
1098     }}
1099     return -1;
1100 }}
1101 QHash<int, QByteArray> {0}::roleNames() const {{
1102     QHash<int, QByteArray> names = QAbstractItemModel::roleNames();",
1103         o.name
1104     )?;
1105     for (i, (name, _)) in o.item_properties.iter().enumerate() {
1106         writeln!(w, "    names.insert(Qt::UserRole + {}, \"{}\");", i, name)?;
1107     }
1108     writeln!(
1109         w,
1110         "    return names;
1111 }}
1112 QVariant {0}::headerData(int section, Qt::Orientation orientation, int role) const
1113 {{
1114     if (orientation != Qt::Horizontal) {{
1115         return QVariant();
1116     }}
1117     return m_headerData.value(qMakePair(section, (Qt::ItemDataRole)role), role == Qt::DisplayRole ?QString::number(section + 1) :QVariant());
1118 }}
1119 
1120 bool {0}::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role)
1121 {{
1122     if (orientation != Qt::Horizontal) {{
1123         return false;
1124     }}
1125     m_headerData.insert(qMakePair(section, (Qt::ItemDataRole)role), value);
1126     return true;
1127 }}
1128 ",
1129         o.name
1130     )?;
1131     if model_is_writable(o) {
1132         writeln!(
1133             w,
1134             "bool {}::setData(const QModelIndex &index, const QVariant &value, int role)\n{{",
1135             o.name
1136         )?;
1137         for col in 0..o.column_count() {
1138             if !is_column_write(o, col) {
1139                 continue;
1140             }
1141             writeln!(w, "    if (index.column() == {}) {{", col)?;
1142             for (i, (name, ip)) in o.item_properties.iter().enumerate() {
1143                 if !ip.write {
1144                     continue;
1145                 }
1146                 let empty = Vec::new();
1147                 let roles = ip.roles.get(col).unwrap_or(&empty);
1148                 if col > 0 && roles.is_empty() {
1149                     continue;
1150                 }
1151                 write!(w, "        if (")?;
1152                 for role in roles {
1153                     write!(w, "role == Qt::{} || ", role_name(role))?;
1154                 }
1155                 writeln!(w, "role == Qt::UserRole + {}) {{", i)?;
1156                 let ii = if o.object_type == ObjectType::List {
1157                     ".row()"
1158                 } else {
1159                     ""
1160                 };
1161                 if ip.optional && !ip.is_complex() {
1162                     writeln!(
1163                         w,
1164                         "            return set{}(index{}, value);",
1165                         upper_initial(name),
1166                         ii
1167                     )?;
1168                 } else {
1169                     let pre = if ip.optional {
1170                         "!value.isValid() || value.isNull() ||"
1171                     } else {
1172                         ""
1173                     };
1174                     writeln!(
1175                         w,
1176                         "            if ({}value.canConvert(qMetaTypeId<{}>())) {{",
1177                         pre,
1178                         ip.type_name()
1179                     )?;
1180                     writeln!(
1181                         w,
1182                         "                return set{}(index{}, value.value<{}>());",
1183                         upper_initial(name),
1184                         ii,
1185                         ip.type_name()
1186                     )?;
1187                     writeln!(w, "            }}")?;
1188                 }
1189                 writeln!(w, "        }}")?;
1190             }
1191             writeln!(w, "    }}")?;
1192         }
1193         writeln!(w, "    return false;\n}}\n")?;
1194     }
1195     Ok(())
1196 }
1197 
1198 fn constructor_args_decl(w: &mut Vec<u8>, o: &Object, conf: &Config) -> Result<()> {
1199     write!(w, "{}*", o.name)?;
1200     for p in o.properties.values() {
1201         if let Type::Object(object) = &p.property_type {
1202             write!(w, ", ")?;
1203             constructor_args_decl(w, object, conf)?;
1204         } else {
1205             write!(w, ", void (*)({}*)", o.name)?;
1206         }
1207     }
1208     if o.object_type == ObjectType::List {
1209         write!(
1210             w,
1211             ",
1212         void (*)(const {}*),
1213         void (*)({0}*),
1214         void (*)({0}*),
1215         void (*)({0}*, quintptr, quintptr),
1216         void (*)({0}*),
1217         void (*)({0}*),
1218         void (*)({0}*, int, int),
1219         void (*)({0}*),
1220         void (*)({0}*, int, int, int),
1221         void (*)({0}*),
1222         void (*)({0}*, int, int),
1223         void (*)({0}*)",
1224             o.name
1225         )?;
1226     }
1227     if o.object_type == ObjectType::Tree {
1228         write!(
1229             w,
1230             ",
1231         void (*)(const {0}*, option_quintptr),
1232         void (*)({0}*),
1233         void (*)({0}*),
1234         void (*)({0}*, quintptr, quintptr),
1235         void (*)({0}*),
1236         void (*)({0}*),
1237         void (*)({0}*, option_quintptr, int, int),
1238         void (*)({0}*),
1239         void (*)({0}*, option_quintptr, int, int, option_quintptr, int),
1240         void (*)({0}*),
1241         void (*)({0}*, option_quintptr, int, int),
1242         void (*)({0}*)",
1243             o.name
1244         )?;
1245     }
1246     Ok(())
1247 }
1248 
1249 fn changed_f(o: &Object, p_name: &str) -> String {
1250     lower_initial(&o.name) + &upper_initial(p_name) + "Changed"
1251 }
1252 
1253 fn constructor_args(w: &mut Vec<u8>, prefix: &str, o: &Object, conf: &Config) -> Result<()> {
1254     let lcname = snake_case(&o.name);
1255     for (name, p) in &o.properties {
1256         if let Type::Object(object) = &p.property_type {
1257             write!(w, ", {}m_{}", prefix, name)?;
1258             constructor_args(w, &format!("m_{}->", name), object, conf)?;
1259         } else {
1260             write!(w, ",\n        {}", changed_f(o, name))?;
1261         }
1262     }
1263     if o.object_type == ObjectType::List {
1264         writeln!(
1265             w,
1266             ",
1267         [](const {0}* o) {{
1268             Q_EMIT o->newDataReady(QModelIndex());
1269         }},
1270         []({0}* o) {{
1271             Q_EMIT o->layoutAboutToBeChanged();
1272         }},
1273         []({0}* o) {{
1274             o->updatePersistentIndexes();
1275             Q_EMIT o->layoutChanged();
1276         }},
1277         []({0}* o, quintptr first, quintptr last) {{
1278             o->dataChanged(o->createIndex(first, 0, first),
1279                        o->createIndex(last, {1}, last));
1280         }},
1281         []({0}* o) {{
1282             o->beginResetModel();
1283         }},
1284         []({0}* o) {{
1285             o->endResetModel();
1286         }},
1287         []({0}* o, int first, int last) {{
1288             o->beginInsertRows(QModelIndex(), first, last);
1289         }},
1290         []({0}* o) {{
1291             o->endInsertRows();
1292         }},
1293         []({0}* o, int first, int last, int destination) {{
1294             o->beginMoveRows(QModelIndex(), first, last, QModelIndex(), destination);
1295         }},
1296         []({0}* o) {{
1297             o->endMoveRows();
1298         }},
1299         []({0}* o, int first, int last) {{
1300             o->beginRemoveRows(QModelIndex(), first, last);
1301         }},
1302         []({0}* o) {{
1303             o->endRemoveRows();
1304         }}",
1305             o.name,
1306             o.column_count() - 1
1307         )?;
1308     }
1309     if o.object_type == ObjectType::Tree {
1310         writeln!(
1311             w,
1312             ",
1313         [](const {0}* o, option_quintptr id) {{
1314             if (id.some) {{
1315                 int row = {1}_row(o->m_d, id.value);
1316                 Q_EMIT o->newDataReady(o->createIndex(row, 0, id.value));
1317             }} else {{
1318                 Q_EMIT o->newDataReady(QModelIndex());
1319             }}
1320         }},
1321         []({0}* o) {{
1322             Q_EMIT o->layoutAboutToBeChanged();
1323         }},
1324         []({0}* o) {{
1325             o->updatePersistentIndexes();
1326             Q_EMIT o->layoutChanged();
1327         }},
1328         []({0}* o, quintptr first, quintptr last) {{
1329             quintptr frow = {1}_row(o->m_d, first);
1330             quintptr lrow = {1}_row(o->m_d, first);
1331             o->dataChanged(o->createIndex(frow, 0, first),
1332                        o->createIndex(lrow, {2}, last));
1333         }},
1334         []({0}* o) {{
1335             o->beginResetModel();
1336         }},
1337         []({0}* o) {{
1338             o->endResetModel();
1339         }},
1340         []({0}* o, option_quintptr id, int first, int last) {{
1341             if (id.some) {{
1342                 int row = {1}_row(o->m_d, id.value);
1343                 o->beginInsertRows(o->createIndex(row, 0, id.value), first, last);
1344             }} else {{
1345                 o->beginInsertRows(QModelIndex(), first, last);
1346             }}
1347         }},
1348         []({0}* o) {{
1349             o->endInsertRows();
1350         }},
1351         []({0}* o, option_quintptr sourceParent, int first, int last, option_quintptr destinationParent, int destination) {{
1352             QModelIndex s;
1353             if (sourceParent.some) {{
1354                 int row = {1}_row(o->m_d, sourceParent.value);
1355                 s = o->createIndex(row, 0, sourceParent.value);
1356             }}
1357             QModelIndex d;
1358             if (destinationParent.some) {{
1359                 int row = {1}_row(o->m_d, destinationParent.value);
1360                 d = o->createIndex(row, 0, destinationParent.value);
1361             }}
1362             o->beginMoveRows(s, first, last, d, destination);
1363         }},
1364         []({0}* o) {{
1365             o->endMoveRows();
1366         }},
1367         []({0}* o, option_quintptr id, int first, int last) {{
1368             if (id.some) {{
1369                 int row = {1}_row(o->m_d, id.value);
1370                 o->beginRemoveRows(o->createIndex(row, 0, id.value), first, last);
1371             }} else {{
1372                 o->beginRemoveRows(QModelIndex(), first, last);
1373             }}
1374         }},
1375         []({0}* o) {{
1376             o->endRemoveRows();
1377         }}",
1378             o.name,
1379             lcname,
1380             o.column_count() - 1
1381         )?;
1382     }
1383     Ok(())
1384 }
1385 
1386 pub fn write_header(conf: &Config) -> Result<()> {
1387     let mut h_file = conf.config_file.parent().unwrap().join(&conf.cpp_file);
1388     h_file.set_extension("h");
1389     let mut h = Vec::new();
1390     let guard = h_file
1391         .file_name()
1392         .unwrap()
1393         .to_string_lossy()
1394         .replace('.', "_")
1395         .to_uppercase();
1396     writeln!(
1397         h,
1398         "/* generated by rust_qt_binding_generator */
1399 #ifndef {0}
1400 #define {0}
1401 
1402 #include <QtCore/QObject>
1403 #include <QtCore/QAbstractItemModel>
1404 ",
1405         guard
1406     )?;
1407 
1408     for name in conf.objects.keys() {
1409         writeln!(h, "class {};", name)?;
1410     }
1411     for object in conf.objects.values() {
1412         write_header_object(&mut h, object, conf)?;
1413     }
1414     writeln!(h, "#endif // {}", guard)?;
1415 
1416     write_if_different(h_file, &h)?;
1417     Ok(())
1418 }
1419 
1420 pub fn write_cpp(conf: &Config) -> Result<()> {
1421     let mut w = Vec::new();
1422     let mut h_file = conf.config_file.parent().unwrap().join(&conf.cpp_file);
1423     h_file.set_extension("h");
1424     let file_name = h_file.file_name().unwrap().to_string_lossy();
1425     writeln!(
1426         w,
1427         "/* generated by rust_qt_binding_generator */
1428 #include \"{}\"
1429 
1430 namespace {{",
1431         file_name
1432     )?;
1433     for option in conf.optional_types() {
1434         if option != "QString" && option != "QByteArray" {
1435             writeln!(
1436                 w,
1437                 "
1438     struct option_{} {{
1439     public:
1440         {0} value;
1441         bool some;
1442         operator QVariant() const {{
1443             if (some) {{
1444                 return QVariant::fromValue(value);
1445             }}
1446             return QVariant();
1447         }}
1448     }};
1449     static_assert(std::is_pod<option_{0}>::value, \"option_{0} must be a POD type.\");",
1450                 option
1451             )?;
1452         }
1453     }
1454     if conf.types().contains("QString") {
1455         writeln!(
1456             w,
1457             "
1458     typedef void (*qstring_set)(QString* val, const char* utf8, int nbytes);
1459     void set_qstring(QString* val, const char* utf8, int nbytes) {{
1460         *val = QString::fromUtf8(utf8, nbytes);
1461     }}"
1462         )?;
1463     }
1464     if conf.types().contains("QByteArray") {
1465         writeln!(
1466             w,
1467             "
1468     typedef void (*qbytearray_set)(QByteArray* val, const char* bytes, int nbytes);
1469     void set_qbytearray(QByteArray* v, const char* bytes, int nbytes) {{
1470         if (v->isNull() && nbytes == 0) {{
1471             *v = QByteArray(bytes, nbytes);
1472         }} else {{
1473             v->truncate(0);
1474             v->append(bytes, nbytes);
1475         }}
1476     }}"
1477         )?;
1478     }
1479     if conf.has_list_or_tree() {
1480         writeln!(
1481             w,
1482             "
1483     struct qmodelindex_t {{
1484         int row;
1485         quintptr id;
1486     }};
1487     inline QVariant cleanNullQVariant(const QVariant& v) {{
1488         return (v.isNull()) ?QVariant() :v;
1489     }}"
1490         )?;
1491     }
1492     for (name, o) in &conf.objects {
1493         for (p_name, p) in &o.properties {
1494             if p.is_object() {
1495                 continue;
1496             }
1497             writeln!(w, "    inline void {}({}* o)", changed_f(o, p_name), name)?;
1498             writeln!(w, "    {{\n        Q_EMIT o->{}Changed();\n    }}", p_name)?;
1499         }
1500     }
1501     writeln!(w, "}}")?;
1502 
1503     for o in conf.objects.values() {
1504         if o.object_type != ObjectType::Object {
1505             write_cpp_model(&mut w, o)?;
1506         }
1507         writeln!(w, "extern \"C\" {{")?;
1508         write_object_c_decl(&mut w, o, conf)?;
1509         writeln!(w, "}};\n")?;
1510     }
1511 
1512     for o in conf.objects.values() {
1513         write_cpp_object(&mut w, o, conf)?;
1514     }
1515 
1516     writeln!(w, "extern \"C\" {{
1517     void qmetaobject__invokeMethod__0(QObject *obj, const char *member) {{
1518         QMetaObject::invokeMethod(obj, member);
1519     }}
1520 }}")?;
1521 
1522 
1523     let file = conf.config_file.parent().unwrap().join(&conf.cpp_file);
1524     write_if_different(file, &w)
1525 }