fn output_struct_or_variant_container()

in serde-generate/src/dart.rs [609:889]


    fn output_struct_or_variant_container(
        &mut self,
        variant_base: Option<&str>,
        variant_index: Option<u32>,
        name: &str,
        fields: &[Named<Format>],
    ) -> Result<()> {
        let field_count = fields.len();

        // Beginning of class
        writeln!(self.out)?;
        self.output_comment(name)?;
        if let Some(base) = variant_base {
            writeln!(
                self.out,
                "@immutable\nclass {} extends {} {{",
                self.quote_qualified_name(name),
                base
            )?;
        } else {
            writeln!(
                self.out,
                "@immutable\nclass {} {{",
                self.quote_qualified_name(name)
            )?;
        }
        self.enter_class(name);

        // Constructor.
        writeln!(
            self.out,
            "const {}({}",
            self.quote_qualified_name(name),
            if !fields.is_empty() { "{" } else { "" }
        )?;
        self.out.indent();
        for field in fields.iter() {
            let field_name = self.quote_field(&field.name.to_mixed_case());
            match &field.value {
                Format::Option(_) => writeln!(self.out, "this.{},", field_name)?,
                _ => writeln!(self.out, "required this.{},", field_name)?,
            }
        }
        self.out.unindent();
        if variant_base.is_some() {
            writeln!(
                self.out,
                "{}) : super();",
                if !fields.is_empty() { "}" } else { "" }
            )?;
        } else {
            writeln!(self.out, "{});", if !fields.is_empty() { "}" } else { "" })?;
        }

        if self.generator.config.serialization {
            // a struct (UnitStruct) with zero fields
            if variant_index.is_none() && fields.is_empty() {
                writeln!(
                    self.out,
                    "\n{}.deserialize(BinaryDeserializer deserializer);",
                    self.quote_qualified_name(name)
                )?;
            // Deserialize (struct) or Load (variant)
            } else if variant_index.is_none() {
                writeln!(
                    self.out,
                    "\n{}.deserialize(BinaryDeserializer deserializer) :",
                    self.quote_qualified_name(name)
                )?;
            } else if !fields.is_empty() {
                writeln!(
                    self.out,
                    "\n{}.load(BinaryDeserializer deserializer) :",
                    self.quote_qualified_name(name)
                )?;
            } else {
                writeln!(
                    self.out,
                    "\n{}.load(BinaryDeserializer deserializer);",
                    self.quote_qualified_name(name)
                )?;
            }

            self.out.indent();
            for (index, field) in fields.iter().enumerate() {
                if index == field_count - 1 {
                    writeln!(
                        self.out,
                        "{} = {};",
                        self.quote_field(&field.name.to_mixed_case()),
                        self.quote_deserialize(&field.value)
                    )?;
                } else {
                    writeln!(
                        self.out,
                        "{} = {},",
                        self.quote_field(&field.name.to_mixed_case()),
                        self.quote_deserialize(&field.value)
                    )?;
                }
            }
            self.out.unindent();

            if variant_index.is_none() {
                for encoding in &self.generator.config.encodings {
                    self.output_class_deserialize_for_encoding(name, *encoding)?;
                }
            }
        }

        // Fields
        if !fields.is_empty() {
            writeln!(self.out)?;
        }
        for field in fields {
            writeln!(
                self.out,
                "final {} {};",
                self.quote_type(&field.value),
                self.quote_field(&field.name.to_mixed_case())
            )?;
        }
        if !fields.is_empty() {
            writeln!(self.out)?;
        }

        // Serialize
        if self.generator.config.serialization {
            writeln!(self.out, "\nvoid serialize(BinarySerializer serializer) {{",)?;
            self.out.indent();
            if let Some(index) = variant_index {
                writeln!(self.out, "serializer.serializeVariantIndex({});", index)?;
            }
            for field in fields {
                writeln!(
                    self.out,
                    "{}",
                    self.quote_serialize_value(
                        &self.quote_field(&field.name.to_mixed_case()),
                        &field.value
                    )
                )?;
            }
            self.out.unindent();
            writeln!(self.out, "}}")?;

            if variant_index.is_none() {
                for encoding in &self.generator.config.encodings {
                    self.output_class_serialize_for_encoding(*encoding)?;
                }
            }
        }

        // Equality
        write!(self.out, "\n@override")?;
        write!(self.out, "\nbool operator ==(Object other) {{")?;
        self.out.indent();

        writeln!(self.out, "\nif (identical(this, other)) return true;")?;
        writeln!(
            self.out,
            "if (other.runtimeType != runtimeType) return false;"
        )?;
        writeln!(self.out, "\nreturn other is {}", name)?;

        for field in fields.iter() {
            let stmt = match &field.value {
                Format::Seq(_) => {
                    format!(
                        " listEquals({0}, other.{0})",
                        self.quote_field(&field.name.to_mixed_case())
                    )
                }
                Format::TupleArray {
                    content: _,
                    size: _,
                } => format!(
                    " listEquals({0}, other.{0})",
                    self.quote_field(&field.name.to_mixed_case())
                ),
                Format::Map { .. } => {
                    format!(
                        " mapEquals({0}, other.{0})",
                        self.quote_field(&field.name.to_mixed_case())
                    )
                }
                _ => format!(
                    " {0} == other.{0}",
                    self.quote_field(&field.name.to_mixed_case())
                ),
            };

            writeln!(self.out, "&& {}", stmt)?;
        }

        write!(self.out, ";")?;

        self.out.unindent();
        writeln!(self.out, "}}")?;

        // Hashing
        if field_count > 0 {
            write!(self.out, "\n@override")?;

            if field_count == 1 {
                writeln!(
                    self.out,
                    "\nint get hashCode => {}.hashCode;",
                    fields.first().unwrap().name.to_mixed_case()
                )?;
            } else {
                let use_hash_all = field_count > 20;

                if use_hash_all {
                    writeln!(self.out, "\nint get hashCode => Object.hashAll([")?;
                } else {
                    writeln!(self.out, "\nint get hashCode => Object.hash(")?;
                }

                self.out.indent();
                self.out.indent();
                self.out.indent();

                for field in fields {
                    writeln!(
                        self.out,
                        "{},",
                        self.quote_field(&field.name.to_mixed_case())
                    )?;
                }

                self.out.unindent();

                if use_hash_all {
                    writeln!(self.out, "]);")?;
                } else {
                    writeln!(self.out, ");")?;
                }

                self.out.unindent();
                self.out.unindent();
            }
        }

        // Generate a toString implementation in each class
        writeln!(self.out, "\n@override\nString toString() {{")?;
        self.out.indent();
        writeln!(self.out, "String? fullString;")?;
        writeln!(self.out, "\nassert(() {{")?;
        self.out.indent();
        writeln!(self.out, "fullString = '$runtimeType('")?;
        self.out.indent();
        for (index, field) in fields.iter().enumerate() {
            if index == field_count - 1 {
                writeln!(
                    self.out,
                    "'{0}: ${0}'",
                    self.quote_field(&field.name.to_mixed_case())
                )?;
            } else {
                writeln!(
                    self.out,
                    "'{0}: ${0}, '",
                    self.quote_field(&field.name.to_mixed_case())
                )?;
            }
        }
        writeln!(self.out, "')';")?;
        self.out.unindent();
        writeln!(self.out, "return true;")?;
        self.out.unindent();
        writeln!(self.out, "}}());")?;
        writeln!(self.out, "\nreturn fullString ?? '{}';", name)?;
        self.out.unindent();
        writeln!(self.out, "}}")?;

        self.out.unindent();
        // End of class
        self.leave_class();
        writeln!(self.out, "}}")
    }