planus-codegen 1.3.0

Internal codegen library for planus.
Documentation
{% for docstring in docstrings.iter_strings() %}
/// {{ docstring }}
{%- endfor %}
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd,
{% if info.should_do_eq %}Eq, Ord, Hash,{% endif %}
{% if info.should_do_default %}Default, {% endif %}
::serde::Serialize, ::serde::Deserialize
)]
pub struct {{ info.owned_name }} {
    {% for field in fields -%}
        {% for docstring in field.name_and_docs.docstrings.iter_strings() %}
        /// {{ docstring }}
        {%- endfor %}
        pub {{ field.info.name }}: {{ field.info.owned_type }},
    {% endfor %}
}

/// # Safety
/// The Planus compiler correctly calculates `ALIGNMENT` and `SIZE`.
unsafe impl ::planus::Primitive for {{ info.owned_name }} {
    const ALIGNMENT: usize = {{ alignment }};
    const SIZE: usize = {{ size }};
}

#[allow(clippy::identity_op)]
impl ::planus::WriteAsPrimitive<{{ info.owned_name }}> for {{ info.owned_name }} {
    #[inline]
    fn write<const N: usize>(&self, cursor: ::planus::Cursor<'_, N>, buffer_position: u32) {
        {% for field in fields -%}
            let (cur, cursor) = cursor.split::<{{ field.size }} , {{ size - field.offset - field.size }}>();
            self.{{ field.info.name }}.write(cur, buffer_position - {{ field.offset }});
            {%- if field.padding_after_field != 0 -%}
            let cursor = cursor.write::<{{ field.padding_after_field }}, {{ size - field.offset - field.size - field.padding_after_field }}>([0; {{ field.padding_after_field }}]);
            {%- endif -%}
        {% endfor %}
        cursor.finish([]);
    }
}

impl ::planus::WriteAsOffset<{{ info.owned_name }}> for {{ info.owned_name }} {
    #[inline]
    fn prepare(&self, builder: &mut ::planus::Builder) -> ::planus::Offset<{{info.owned_name}}> {
        unsafe {
            builder.write_with(
                {{ size }},
                {{ alignment - 1 }},
                |buffer_position, bytes| {
                    let bytes = bytes.as_mut_ptr();

                    ::planus::WriteAsPrimitive::write(
                        self,
                        ::planus::Cursor::new(&mut *(bytes as *mut [::core::mem::MaybeUninit<u8>; {{ size }}])),
                        buffer_position,
                    );
                }
            );
        }
        builder.current_offset()
    }
}

impl ::planus::WriteAs<{{ info.owned_name }}> for {{ info.owned_name }} {
    type Prepared = Self;
    #[inline]
    fn prepare(&self, _builder: &mut ::planus::Builder) -> Self {
        *self
    }
}

impl ::planus::WriteAsOptional<{{ info.owned_name }}> for {{ info.owned_name }} {
    type Prepared = Self;
    #[inline]
    fn prepare(&self, _builder: &mut ::planus::Builder) -> ::core::option::Option<Self> {
        ::core::option::Option::Some(*self)
    }
}

/// Reference to a deserialized [{{info.owned_name}}].
#[derive(Copy, Clone)]
pub struct {{ info.ref_name }}<'a>(::planus::ArrayWithStartOffset<'a, {{ size }}>);

impl<'a> {{ info.ref_name }}<'a> {
    {% for field in fields %}
        /// Getter for the [`{{field.name_and_docs.original_name}}` field]({{info.owned_name}}#structfield.{{field.info.name}}).
        pub fn {{ field.info.name }}(&self) -> {{ field.info.getter_return_type }} {
            let buffer = self.0.advance_as_array::<{{field.size}}>({{field.offset}}).unwrap();
            {% if field.info.getter_return_type.starts_with("planus::Result<") %}
            {{ field.info.getter_code }}.map_err(|error_kind| error_kind.with_error_location(
                "{{info.ref_name}}",
                "{{field.info.name}}",
                self.0.offset_from_start,
            ))
            {% else %}
            {{ field.info.getter_code }}
            {% endif %}
        }
    {% endfor %}
}

impl<'a> ::core::fmt::Debug for {{ info.ref_name }}<'a> {
    fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
        let mut f = f.debug_struct("{{info.ref_name}}");
        {% for field in fields -%}
            {%- if field.info.getter_return_type.starts_with("planus::Result<") -%}
                if let ::core::option::Option::Some(field_{{field.info.name}}) = self.{{field.info.name}}().transpose() {
                    f.field("{{field.info.name}}", &field_{{field.info.name}});
                }
            {%- else -%}
                f.field("{{field.info.name}}", &self.{{field.info.name}}());
            {%- endif -%}
        {%- endfor %}
        f.finish()
    }
}

impl<'a> ::core::convert::From<::planus::ArrayWithStartOffset<'a, {{ size }}>> for {{ info.ref_name }}<'a> {
    fn from(array: ::planus::ArrayWithStartOffset<'a, {{ size }}>) -> Self {
        Self(array)
    }
}

{% if info.should_do_infallible_conversion -%}
impl<'a> ::core::convert::From<{{ info.ref_name }}<'a>> for {{ info.owned_name}} {
    #[allow(unreachable_code)]
    fn from(value: {{info.ref_name}}<'a>) -> Self {
        Self {
        {% for field in fields -%}
            {{ field.info.name }}:
            {% if field.info.getter_return_type.ends_with("<'a>") -%}
                ::core::convert::From::from(value.{{field.info.name}}()),
            {% else -%}
                value.{{field.info.name}}(),
            {% endif %}
        {%- endfor %}
        }
    }
}

impl<'a, 'b> ::core::cmp::PartialEq<{{ info.ref_name }}<'a>> for {{ info.ref_name }}<'b> {
    fn eq(&self, other: &{{info.ref_name}}<'_>) -> bool {
        {% for field in fields -%}
            {% if !loop.first %} && {% endif %}
            self.{{field.info.name}}() == other.{{field.info.name}}()
        {%- endfor %}
    }
}
{% if  info.should_do_eq %}
    impl<'a> ::core::cmp::Eq for {{ info.ref_name}}<'a> {}
    impl<'a, 'b> ::core::cmp::PartialOrd<{{ info.ref_name }}<'a>> for {{ info.ref_name }}<'b> {
        fn partial_cmp(&self, other: &{{info.ref_name}}<'_>) -> ::core::option::Option<::core::cmp::Ordering> {
            ::core::option::Option::Some(::core::cmp::Ord::cmp(self, other))
        }
    }

    impl<'a> ::core::cmp::Ord for {{ info.ref_name }}<'a> {
        fn cmp(&self, other: &{{info.ref_name}}<'_>) -> ::core::cmp::Ordering {
            {% for field in fields -%}
                {% if loop.first %}
                self.{{field.info.name}}().cmp(&other.{{field.info.name}}())
                {% else %}
                .then_with(|| self.{{field.info.name}}().cmp(&other.{{field.info.name}}()))
                {% endif %}
            {%- endfor %}
        }
    }

    impl<'a> ::core::hash::Hash for {{ info.ref_name }}<'a> {
        fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
            {% for field in fields -%}
                self.{{field.info.name}}().hash(state);
            {%- endfor %}
        }
    }
{% else %}
    impl<'a, 'b> ::core::cmp::PartialOrd<{{ info.ref_name }}<'a>> for {{ info.ref_name }}<'b> {
        fn partial_cmp(&self, other: &{{info.ref_name}}<'_>) -> ::core::option::Option<::core::cmp::Ordering> {
            {% for field in fields -%}
                {% if loop.last %}
                self.{{field.info.name}}().partial_cmp(&other.{{field.info.name}}())
                {% else %}
                match self.{{field.info.name}}().partial_cmp(&other.{{field.info.name}}()) {
                    ::core::option::Option::Some(::core::cmp::Ordering::Equal) => (),
                    o => return o,
                }
                {% endif %}
            {%- endfor %}
        }
    }
{% endif %}
{%- else -%}
impl<'a> ::core::convert::TryFrom<{{ info.ref_name }}<'a>> for {{ info.owned_name}} {
    type Error = ::planus::Error;

    #[allow(unreachable_code)]
    fn try_from(value: {{info.ref_name}}<'a>) -> ::planus::Result<Self> {
        ::core::result::Result::Ok(Self {
        {% for field in fields -%}
            {{ field.info.name }}:
            {% if field.info.getter_return_type.starts_with("::core::result::Result<") -%}
                {%- if field.info.can_do_infallible_conversion -%}
                    value.{{field.info.name}}()?,
                {%- else -%}
                    ::core::convert::TryInto::try_into(value.{{field.info.name}}()?)?,
                {%- endif -%}
            {% else if field.info.getter_return_type.ends_with("<'a>") -%}
                {%- if field.info.can_do_infallible_conversion -%}
                    ::core::convert::Into::into(value.{{field.info.name}}()),
                {%- else -%}
                    ::core::convert::TryInto::try_into(value.{{field.info.name}}())?,
                {%- endif -%}
            {% else -%}
                value.{{field.info.name}}(),
            {% endif -%}
        {%- endfor %}
        })
    }
}
{%- endif %}

impl<'a> ::planus::TableRead<'a> for {{ info.ref_name }}<'a> {
    #[inline]
    fn from_buffer(buffer: ::planus::SliceWithStartOffset<'a>, offset: usize) -> ::core::result::Result<Self, ::planus::errors::ErrorKind> {
        let buffer = buffer.advance_as_array::<{{size}}>(offset)?;
        ::core::result::Result::Ok(Self(buffer))
    }
}

impl<'a> ::planus::VectorRead<'a> for {{ info.ref_name }}<'a> {
    const STRIDE: usize = {{ size }};

    #[inline]
    unsafe fn from_buffer(buffer: ::planus::SliceWithStartOffset<'a>, offset: usize) -> Self {
        Self(unsafe { buffer.unchecked_advance_as_array(offset) })
    }
}

/// # Safety
/// The planus compiler generates implementations that initialize
/// the bytes in `write_values`.
unsafe impl ::planus::VectorWrite<{{ info.owned_name }}> for {{ info.owned_name }} {
    const STRIDE: usize = {{ size }};

    type Value = {{ info.owned_name }};

    #[inline]
    fn prepare(&self, _builder: &mut ::planus::Builder) -> Self::Value {
        *self
    }

    #[inline]
    unsafe fn write_values(
        values: &[{{info.owned_name}}],
        bytes: *mut ::core::mem::MaybeUninit<u8>,
        buffer_position: u32,
    ) {
        let bytes = bytes as *mut [::core::mem::MaybeUninit<u8>; {{ size }}];
        for (i, v) in ::core::iter::Iterator::enumerate(values.iter()) {
            ::planus::WriteAsPrimitive::write(
                v,
                ::planus::Cursor::new(unsafe { &mut *bytes.add(i) }),
                {% if size == 1 %}
                buffer_position - i as u32,
                {% else %}
                buffer_position - ({{ size }} * i) as u32,
                {% endif %}
            );
        }
    }
}