fn write_derived_cpp_ops()

in src/bindgen/language_backend/clike.rs [119:338]


    fn write_derived_cpp_ops<W: Write>(&mut self, out: &mut SourceWriter<W>, s: &Struct) {
        let mut wrote_start_newline = false;

        if self.config.structure.derive_constructor(&s.annotations) && !s.fields.is_empty() {
            if !wrote_start_newline {
                wrote_start_newline = true;
                out.new_line();
            }

            out.new_line();

            let renamed_fields: Vec<_> = s
                .fields
                .iter()
                .map(|field| {
                    self.config
                        .function
                        .rename_args
                        .apply(&field.name, IdentifierType::FunctionArg)
                        .into_owned()
                })
                .collect();
            write!(out, "{}(", s.export_name());
            let vec: Vec<_> = s
                .fields
                .iter()
                .zip(&renamed_fields)
                .map(|(field, renamed)| {
                    Field::from_name_and_type(
                        // const-ref args to constructor
                        format!("const& {}", renamed),
                        field.ty.clone(),
                    )
                })
                .collect();
            out.write_vertical_source_list(self, &vec[..], ListType::Join(","), Self::write_field);
            write!(out, ")");
            out.new_line();
            write!(out, "  : ");
            let vec: Vec<_> = s
                .fields
                .iter()
                .zip(&renamed_fields)
                .map(|(field, renamed)| format!("{}({})", field.name, renamed))
                .collect();
            out.write_vertical_source_list(self, &vec[..], ListType::Join(","), |_, out, s| {
                write!(out, "{}", s)
            });
            out.new_line();
            write!(out, "{{}}");
            out.new_line();
        }

        let other = self
            .config
            .function
            .rename_args
            .apply("other", IdentifierType::FunctionArg);

        if s.annotations
            .bool("internal-derive-bitflags")
            .unwrap_or(false)
        {
            assert_eq!(s.fields.len(), 1);
            let bits = &s.fields[0].name;
            if !wrote_start_newline {
                wrote_start_newline = true;
                out.new_line();
            }
            let constexpr_prefix = if self.config.constant.allow_constexpr {
                "constexpr "
            } else {
                ""
            };

            out.new_line();
            write!(out, "{}explicit operator bool() const", constexpr_prefix);
            out.open_brace();
            write!(out, "return !!{bits};");
            out.close_brace(false);

            out.new_line();
            write!(
                out,
                "{}{} operator~() const",
                constexpr_prefix,
                s.export_name()
            );
            out.open_brace();
            write!(
                out,
                "return {} {{ static_cast<decltype({bits})>(~{bits}) }};",
                s.export_name()
            );
            out.close_brace(false);
            s.emit_bitflags_binop(constexpr_prefix, '|', &other, out);
            s.emit_bitflags_binop(constexpr_prefix, '&', &other, out);
            s.emit_bitflags_binop(constexpr_prefix, '^', &other, out);
        }

        // Generate a serializer function that allows dumping this struct
        // to an std::ostream. It's defined as a friend function inside the
        // struct definition, and doesn't need the `inline` keyword even
        // though it's implemented right in the generated header file.
        if self.config.structure.derive_ostream(&s.annotations) {
            if !wrote_start_newline {
                wrote_start_newline = true;
                out.new_line();
            }

            out.new_line();
            let stream = self
                .config
                .function
                .rename_args
                .apply("stream", IdentifierType::FunctionArg);
            let instance = self
                .config
                .function
                .rename_args
                .apply("instance", IdentifierType::FunctionArg);
            write!(
                out,
                "friend std::ostream& operator<<(std::ostream& {}, const {}& {})",
                stream,
                s.export_name(),
                instance,
            );
            out.open_brace();
            write!(out, "return {} << \"{{ \"", stream);
            let vec: Vec<_> = s
                .fields
                .iter()
                .map(|x| format!(" << \"{}=\" << {}.{}", x.name, instance, x.name))
                .collect();
            out.write_vertical_source_list(
                self,
                &vec[..],
                ListType::Join(" << \", \""),
                |_, out, s| write!(out, "{}", s),
            );
            out.write(" << \" }\";");
            out.close_brace(false);
        }

        let skip_fields = s.has_tag_field as usize;

        macro_rules! emit_op {
            ($op_name:expr, $op:expr, $conjuc:expr) => {{
                if !wrote_start_newline {
                    #[allow(unused_assignments)]
                    {
                        wrote_start_newline = true;
                    }
                    out.new_line();
                }

                out.new_line();

                if let Some(Some(attrs)) = s.annotations.atom(concat!($op_name, "-attributes")) {
                    write!(out, "{} ", attrs);
                }

                write!(
                    out,
                    "bool operator{}(const {}& {}) const",
                    $op,
                    s.export_name(),
                    other
                );
                out.open_brace();
                out.write("return ");
                let vec: Vec<_> = s
                    .fields
                    .iter()
                    .skip(skip_fields)
                    .map(|field| format!("{} {} {}.{}", field.name, $op, other, field.name))
                    .collect();
                out.write_vertical_source_list(
                    self,
                    &vec[..],
                    ListType::Join(&format!(" {}", $conjuc)),
                    |_, out, s| write!(out, "{}", s),
                );
                out.write(";");
                out.close_brace(false);
            }};
        }

        if self.config.structure.derive_eq(&s.annotations) && s.can_derive_eq() {
            emit_op!("eq", "==", "&&");
        }
        if self.config.structure.derive_neq(&s.annotations) && s.can_derive_eq() {
            emit_op!("neq", "!=", "||");
        }
        if self.config.structure.derive_lt(&s.annotations)
            && s.fields.len() == 1
            && s.fields[0].ty.can_cmp_order()
        {
            emit_op!("lt", "<", "&&");
        }
        if self.config.structure.derive_lte(&s.annotations)
            && s.fields.len() == 1
            && s.fields[0].ty.can_cmp_order()
        {
            emit_op!("lte", "<=", "&&");
        }
        if self.config.structure.derive_gt(&s.annotations)
            && s.fields.len() == 1
            && s.fields[0].ty.can_cmp_order()
        {
            emit_op!("gt", ">", "&&");
        }
        if self.config.structure.derive_gte(&s.annotations)
            && s.fields.len() == 1
            && s.fields[0].ty.can_cmp_order()
        {
            emit_op!("gte", ">=", "&&");
        }
    }