#[derive(Clone, Debug, serde::Serialize, serde::Deserialize{% if not generates_default %}, Default{% endif %})]
{% if has_default %}#[serde(default)]
{% endif %}#[magnus::wrap(class = "{{ class_path }}")]
pub struct {{ struct_name }} {
{% for field in fields %}
{% if field.field_type == 'u64' and (field.name == 'request_timeout' or field.name == 'timeout') %}    #[serde(default = "default_timeout")]
{% endif %}    {{ field.name }}: {{ field.field_type }},
{% endfor %}
}

unsafe impl IntoValueFromNative for {{ struct_name }} {}

impl magnus::TryConvert for {{ struct_name }} {
    fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
        if let Ok(r) = <&{{ struct_name }} as magnus::TryConvert>::try_convert(val) {
            return Ok(r.clone());
        }
        let json_str: String = if let Ok(s) = <String as magnus::TryConvert>::try_convert(val) {
            s
        } else {
            val.funcall::<_, _, String>("to_json", ()).map_err(|e| {
                magnus::Error::new(unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
                    format!("no implicit conversion into {{ struct_name }}: {}", e))
            })?
        };
        serde_json::from_str::<{{ struct_name }}>(&json_str).map_err(|e| {
            magnus::Error::new(unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
                format!("failed to deserialize {{ struct_name }}: {}", e))
        })
    }
}

unsafe impl TryConvertOwned for {{ struct_name }} {}
