// -*- mode: Rust -*-

// AUTOGENERATED BY glean_parser v{{ parser_version }}. DO NOT EDIT. DO NOT COMMIT.
{# The rendered source is autogenerated, but this
Jinja2 template is not. Please file bugs! #}

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

{%- macro generate_structure(name, struct) %}
{%- if struct.type == "oneof" -%}
    #[derive(Debug, Hash, Eq, PartialEq, Clone, ::glean::traits::__serde::Serialize, ::glean::traits::__serde::Deserialize)]
    #[serde(crate = "::glean::traits::__serde")]
    #[serde(untagged)]
    pub enum {{ name }} {
        {% for ty in struct.subtypes %}
          {{ty|Camelize}}({{ty|structure_type_name}}),
        {% endfor %}
    }
{% elif struct.type == "array" %}
    pub type {{ name }} = Vec<{{ name }}Item>;

    {{ generate_structure(name ~ "Item", struct["items"]) }}

{% elif struct.type == "object" %}
    #[derive(Debug, Hash, Eq, PartialEq, Clone, ::glean::traits::__serde::Serialize, ::glean::traits::__serde::Deserialize)]
    #[serde(crate = "::glean::traits::__serde")]
    #[serde(deny_unknown_fields)]
    pub struct {{ name }} {
        {% for itemname, val in struct.properties.items() %}
          {% if val.type == "array" %}
          #[serde(skip_serializing_if = "Vec::is_empty", default = "Vec::new", deserialize_with = "::glean::traits::__serde_helper::vec_null")]
          pub {{itemname|snake_case}}: {{ name ~ itemname|Camelize }},
          {% elif val.type == "object" %}
          #[serde(skip_serializing_if = "Option::is_none")]
          pub {{itemname|snake_case}}: Option<{{ name ~ "Item" ~ itemname|Camelize ~ "Object" }}>,
          {% elif val.type == "oneof" %}
          #[serde(skip_serializing_if = "Option::is_none")]
          pub {{itemname|snake_case}}: Option<{{ name ~ itemname|Camelize ~ "Enum" }}>,
          {% else %}
          #[serde(skip_serializing_if = "Option::is_none")]
          pub {{itemname|snake_case}}: Option<{{val.type|structure_type_name}}>,
          {% endif %}
        {% endfor %}
    }

    {% for itemname, val in struct.properties.items() %}
        {% if val.type == "array" %}
        {% set nested_name = name ~ itemname|Camelize %}
        {{ generate_structure(nested_name, val) }}
        {% elif val.type == "object" %}
        {% set nested_name = name ~ "Item" ~ itemname|Camelize ~ "Object" %}
        {{ generate_structure(nested_name, val) }}
        {% elif val.type == "oneof" %}
        {% set nested_name = name ~ itemname|Camelize ~ "Enum" %}
        {{ generate_structure(nested_name, val) }}
        {% endif %}
    {% endfor %}

{% else %}

pub type {{ name }} = {{ struct.type|structure_type_name }};

{% endif %}

{% endmacro %}

{% macro generate_extra_keys(obj) %}
{% for name, _ in obj["_generate_enums"] %}
{# we always use the `extra` suffix, because we only expose the new event API #}
{% set suffix = "Extra" %}
{% if obj|attr(name)|length %}
    {{ extra_keys_with_types(obj, name, suffix)|indent }}
{% endif %}
{% endfor %}
{% endmacro %}
{% macro extra_keys_with_types(obj, name, suffix) %}
#[derive(Default, Debug, Clone, Hash, Eq, PartialEq)]
pub struct {{ obj.name|Camelize }}{{ suffix }} {
    {% for item, type in obj|attr(name) %}
    pub {{ item|snake_case }}: Option<{{type|extra_type_name}}>,
    {% endfor %}
}

impl ExtraKeys for {{ obj.name|Camelize }}{{ suffix }} {
    const ALLOWED_KEYS: &'static [&'static str] = {{ obj.allowed_extra_keys|extra_keys }};

    fn into_ffi_extra(self) -> ::std::collections::HashMap<::std::string::String, ::std::string::String> {
        let mut map = ::std::collections::HashMap::new();
        {% for key, _ in obj|attr(name) %}
        self.{{key|snake_case}}.and_then(|val| map.insert("{{key}}".to_string(), val.to_string()));
        {% endfor %}
        map
    }
}
{% endmacro %}
{% macro common_metric_data(obj) %}
CommonMetricData {
    category: {{ obj.category|rust }},
    name: {{ obj.name|rust }},
    send_in_pings: {{ obj.send_in_pings|rust }},
    lifetime: {{ obj.lifetime|rust }},
    disabled: {{ obj.is_disabled()|rust }},
    ..Default::default()
}
{%- endmacro -%}
{% for category in categories %}
{% if category.contains_pings %}
{% for obj in category.objs.values() %}
#[allow(non_upper_case_globals, dead_code)]
/// {{ obj.description|wordwrap() | replace('\n', '\n/// ') }}
#[rustfmt::skip]
pub static {{ obj.name|snake_case }}: ::glean::private::__export::Lazy<::glean::private::PingType> =
    ::glean::private::__export::Lazy::new(|| ::glean::private::PingType::new("{{ obj.name }}", {{ obj.include_client_id|rust }}, {{ obj.send_if_empty|rust }}, {{ obj.precise_timestamps|rust }}, {{ obj.include_info_sections|rust }}, {{ obj.enabled|rust }}, {{ obj.schedules_pings|rust }}, {{ obj.reason_codes|rust }}, {{ obj.follows_collection_enabled|rust }}, {{ obj.uploader_capabilities|rust }}));
{% endfor %}
{% else %}
pub mod {{ category.name|snake_case }} {
    #[allow(unused_imports)] // HistogramType might be unusued, let's avoid warnings
    use glean::{private::*, traits::ExtraKeys, traits::NoExtraKeys, CommonMetricData, HistogramType, LabeledMetricData, Lifetime, TimeUnit, MemoryUnit};
    {% for obj in category.objs.values() %}

    {% if obj|attr("_generate_structure") %}
{{ generate_structure(obj.name|Camelize ~ "Object", obj._generate_structure) }}
    {%- endif %}

    {% if obj|attr("_generate_enums") %}
{{ generate_extra_keys(obj) }}
    {%- endif %}
    #[allow(non_upper_case_globals, dead_code)]
    /// generated from {{ category.name }}.{{ obj.name }}
    ///
    /// {{ obj.description|wordwrap() | replace('\n', '\n    /// ') }}
    pub static {{ obj.name|snake_case }}: ::glean::private::__export::Lazy<{{ obj|type_name }}> = ::glean::private::__export::Lazy::new(|| {
        let meta =
            {% if obj.type == "labeled_custom_distribution" %}
            LabeledMetricData::CustomDistribution {
                cmd: {{ common_metric_data(obj)|indent(16) }}
                {%- for arg_name in extra_metric_args if obj[arg_name] is defined and arg_name != 'allowed_extra_keys' -%}
                    , {{ arg_name }}: {{ obj[arg_name]|rust }}
                {%- endfor -%}
            };
            {% elif obj.type == "labeled_memory_distribution" %}
            LabeledMetricData::MemoryDistribution {
                cmd: {{ common_metric_data(obj)|indent(16) }}
                {%- for arg_name in extra_metric_args if obj[arg_name] is defined and arg_name != 'allowed_extra_keys' -%}
                    , {{ "unit" if arg_name == "memory_unit" else arg_name }}: {{ obj[arg_name]|rust }}
                {%- endfor -%}
            };
            {% elif obj.type == "labeled_timing_distribution" %}
            LabeledMetricData::TimingDistribution {
                cmd: {{ common_metric_data(obj)|indent(16) }}
                {%- for arg_name in extra_metric_args if obj[arg_name] is defined and arg_name != 'allowed_extra_keys' -%}
                    , {{ "unit" if arg_name == "time_unit" else arg_name }}: {{ obj[arg_name]|rust }}
                {%- endfor -%}
            };
            {% elif obj.labeled %}
            LabeledMetricData::Common {
                cmd: {{common_metric_data(obj)|indent(16) }},
            };
            {% else %}
            {{ common_metric_data(obj)|indent(12) }};
            {% endif %}
        {{ obj|ctor }}(meta
        {%- for arg_name in extra_metric_args if not obj.labeled and obj[arg_name] is defined and arg_name != 'allowed_extra_keys' -%}
            , {{ obj[arg_name]|rust }}
        {%- endfor -%}
        {{ ", " if obj.labeled or obj.dual_labeled else ")\n" }}
        {%- if obj.labeled -%}
        {%- if obj.labels -%}
        Some({{ obj.labels|rust }})
        {%- else -%}
        None
        {%- endif -%})
        {% endif %}
        {%- if obj.dual_labeled -%}
        {%- if obj.keys -%}
        Some({{ obj.keys|rust }})
        {%- else -%}
        None
        {%- endif -%}
        {{ ", " }}
        {%- if obj.categories -%}
        Some({{ obj.categories|rust }})
        {%- else -%}
        None
        {%- endif -%})
        {% endif %}
    });
    {% endfor %}
}
{% endif %}
{% endfor %}
{% if metric_by_type|length > 0 %}

{% endif %}
