<commit_before>//! the [STAT] table
//!
//! [STAT]: https://docs.microsoft.com/en-us/typography/opentype/spec/stat

use font_types::{
    BigEndian, Fixed, FontRead, MajorMinor, Offset, Offset16, Offset32, OffsetHost, Tag,
};
use zerocopy::LayoutVerified;

/// 'STAT'
pub const TAG: Tag = Tag::new(b"STAT");

font_types::tables! {
    /// [STAT](https://docs.microsoft.com/en-us/typography/opentype/spec/stat) (Style Attributes Table)
    #[offset_host]
    Stat1_0<'a> {
        /// Major version number of the style attributes table — set to 1.
        major_version: BigEndian<u16>,
        /// Minor version number of the style attributes table — set to 2.
        minor_version: BigEndian<u16>,
        /// The size in bytes of each axis record.
        design_axis_size: BigEndian<u16>,
        /// The number of axis records. In a font with an 'fvar' table,
        /// this value must be greater than or equal to the axisCount value
        /// in the 'fvar' table. In all fonts, must be greater than zero if
        /// axisValueCount is greater than zero.
        design_axis_count: BigEndian<u16>,
        /// Offset in bytes from the beginning of the STAT table to the
        /// start of the design axes array. If designAxisCount is zero, set
        /// to zero; if designAxisCount is greater than zero, must be
        /// greater than zero.
        design_axes_offset: BigEndian<Offset32>,
        /// The number of axis value tables.
        axis_value_count: BigEndian<u16>,
        /// Offset in bytes from the beginning of the STAT table to the
        /// start of the design axes value offsets array. If axisValueCount
        /// is zero, set to zero; if axisValueCount is greater than zero,
        /// must be greater than zero.
        offset_to_axis_value_offsets: BigEndian<Offset32>,
    }

    /// [STAT](https://docs.microsoft.com/en-us/typography/opentype/spec/stat) (Style Attributes Table)
    #[offset_host]
    Stat1_2<'a> {
        /// Major version number of the style attributes table — set to 1.
        major_version: BigEndian<u16>,
        /// Minor version number of the style attributes table — set to 2.
        minor_version: BigEndian<u16>,
        /// The size in bytes of each axis record.
        design_axis_size: BigEndian<u16>,
        /// The number of axis records. In a font with an 'fvar' table,
        /// this value must be greater than or equal to the axisCount value
        /// in the 'fvar' table. In all fonts, must be greater than zero if
        /// axisValueCount is greater than zero.
        design_axis_count: BigEndian<u16>,
        /// Offset in bytes from the beginning of the STAT table to the
        /// start of the design axes array. If designAxisCount is zero, set
        /// to zero; if designAxisCount is greater than zero, must be
        /// greater than zero.
        design_axes_offset: BigEndian<Offset32>,
        /// The number of axis value tables.
        axis_value_count: BigEndian<u16>,
        /// Offset in bytes from the beginning of the STAT table to the
        /// start of the design axes value offsets array. If axisValueCount
        /// is zero, set to zero; if axisValueCount is greater than zero,
        /// must be greater than zero.
        offset_to_axis_value_offsets: BigEndian<Offset32>,
        /// Name ID used as fallback when projection of names into a
        /// particular font model produces a subfamily name containing only
        /// elidable elements.
        elided_fallback_name_id: BigEndian<u16>,
    }

    /// [Axis Records](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-records)
    AxisRecord {
        /// A tag identifying the axis of design variation.
        axis_tag: BigEndian<Tag>,
        /// The name ID for entries in the 'name' table that provide a
        /// display string for this axis.
        axis_name_id: BigEndian<u16>,
        /// A value that applications can use to determine primary sorting
        /// of face names, or for ordering of labels when composing family
        /// or face names.
        axis_ordering: BigEndian<u16>,
    }

    /// [STAT](https://docs.microsoft.com/en-us/typography/opentype/spec/stat) (Style Attributes Table)
    #[format(MajorMinor)]
    #[generate_getters]
    enum Stat<'a> {
        #[version(MajorMinor::VERSION_1_0)]
        Version1_0(Stat1_0<'a>),
        #[version(MajorMinor::VERSION_1_2)]
        Version1_2(Stat1_2<'a>),
    }
}

//FIXME: we should generate this automatically?
impl<'a> OffsetHost<'a> for Stat<'a> {
    fn bytes(&self) -> &'a [u8] {
        match self {
            Stat::Version1_0(table) => table.bytes(),
            Stat::Version1_2(table) => table.bytes(),
        }
    }
}

impl<'a> Stat<'a> {
    /// The design-axes array.
    pub fn design_axes(&self) -> impl Iterator<Item = AxisRecord> + '_ {
        let count = self.design_axis_count();
        let offset = self.design_axes_offset();
        let record_len = self.design_axis_size() as usize;
        let bytes = self.bytes_at_offset(offset);
        let mut idx = 0;
        std::iter::from_fn(move || {
            if idx == count as usize {
                return None;
            }
            let rel_off = idx * record_len;
            let result = bytes
                .get(rel_off..rel_off + record_len)
                .and_then(AxisRecord::read);
            idx += 1;
            result
        })
    }

    fn axis_value_offsets(&self) -> &[BigEndian<Offset16>] {
        let count = self.axis_value_count();
        let offset = self.offset_to_axis_value_offsets();
        let bytes = self.bytes_at_offset(offset);
        match LayoutVerified::new_slice_unaligned_from_prefix(bytes, count as usize) {
            Some((layout, _)) => layout.into_slice(),
            None => &[],
        }
    }

    pub fn iter_axis_value_tables(&self) -> impl Iterator<Item = AxisValue<'a>> + '_ {
        let offset_start = self.offset_to_axis_value_offsets();
        let bytes = self.bytes_at_offset(offset_start);
        self.axis_value_offsets().iter().map_while(|off| {
            off.get()
                .non_null()
                .and_then(|off| bytes.get(off..).and_then(AxisValue::read))
        })
    }
}

font_types::tables! {

    /// [Axis Value Tables](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-tables)
    #[format(u16)]
    enum AxisValue<'a> {
        #[version(1)]
        Format1(AxisValueFormat1),
        #[version(2)]
        Format2(AxisValueFormat2),
        #[version(3)]
        Format3(AxisValueFormat3),
        #[version(4)]
        Format4(AxisValueFormat4<'a>),
    }

    /// [Axis value table format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-1)
    AxisValueFormat1 {
        /// Format identifier — set to 1.
        format: BigEndian<u16>,
        /// Zero-base index into the axis record array identifying the axis
        /// of design variation to which the axis value table applies. Must
        /// be less than designAxisCount.
        axis_index: BigEndian<u16>,
        /// Flags — see below for details.
        flags: BigEndian<u16>,
        /// The name ID for entries in the 'name' table that provide a
        /// display string for this attribute value.
        value_name_id: BigEndian<u16>,
        /// A numeric value for this attribute value.
        value: BigEndian<Fixed>,
    }

    /// [Axis value table format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-2)
    AxisValueFormat2 {
        /// Format identifier — set to 2.
        format: BigEndian<u16>,
        /// Zero-base index into the axis record array identifying the axis
        /// of design variation to which the axis value table applies. Must
        /// be less than designAxisCount.
        axis_index: BigEndian<u16>,
        /// Flags — see below for details.
        flags: BigEndian<u16>,
        /// The name ID for entries in the 'name' table that provide a
        /// display string for this attribute value.
        value_name_id: BigEndian<u16>,
        /// A nominal numeric value for this attribute value.
        nominal_value: BigEndian<Fixed>,
        /// The minimum value for a range associated with the specified
        /// name ID.
        range_min_value: BigEndian<Fixed>,
        /// The maximum value for a range associated with the specified
        /// name ID.
        range_max_value: BigEndian<Fixed>,
    }

    /// [Axis value table format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-3)
    AxisValueFormat3 {
        /// Format identifier — set to 3.
        format: BigEndian<u16>,
        /// Zero-base index into the axis record array identifying the axis
        /// of design variation to which the axis value table applies. Must
        /// be less than designAxisCount.
        axis_index: BigEndian<u16>,
        /// Flags — see below for details.
        flags: BigEndian<u16>,
        /// The name ID for entries in the 'name' table that provide a
        /// display string for this attribute value.
        value_name_id: BigEndian<u16>,
        /// A numeric value for this attribute value.
        value: BigEndian<Fixed>,
        /// The numeric value for a style-linked mapping from this value.
        linked_value: BigEndian<Fixed>,
    }

    /// [Axis value table format 4](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-4)
    AxisValueFormat4<'a> {
        /// Format identifier — set to 4.
        format: BigEndian<u16>,
        /// The total number of axes contributing to this axis-values
        /// combination.
        axis_count: BigEndian<u16>,
        /// Flags — see below for details.
        flags: BigEndian<u16>,
        /// The name ID for entries in the 'name' table that provide a
        /// display string for this combination of axis values.
        value_name_id: BigEndian<u16>,
        /// Array of AxisValue records that provide the combination of axis
        /// values, one for each contributing axis.
        #[count(axis_count)]
        axis_values: [AxisValueRecord],
    }

    /// Part of [AxisValueFormat4]
    AxisValueRecord {
        /// Zero-base index into the axis record array identifying the axis
        /// to which this value applies. Must be less than designAxisCount.
        axis_index: BigEndian<u16>,
        /// A numeric value for this attribute value.
        value: BigEndian<Fixed>,
    }

    /// [Axis value table flags](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#flags).
#[flags(u16)]
    AxisValueTableFlags {
        /// If set, this axis value table provides axis value information
        /// that is applicable to other fonts within the same font family.
        /// This is used if the other fonts were released earlier and did
        /// not include information about values for some axis. If newer
        /// versions of the other fonts include the information themselves
        /// and are present, then this table is ignored.
        OLDER_SIBLING_FONT_ATTRIBUTE = 0x0001,
        /// If set, it indicates that the axis value represents the
        /// “normal” value for the axis and may be omitted when
        /// composing name strings.
        ELIDABLE_AXIS_VALUE_NAME = 0x0002,
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn smoke_test() {
        let mut buf = font_types::test_helpers::BeBuffer::new();
        buf.extend([1u16, 0]); // version
        buf.push(std::mem::size_of::<AxisRecord>() as u16); // design axis size
        buf.push(1u16); // design axis count
        buf.push(Offset32::new(18));
        buf.push(2u16);
        buf.push(Offset32::new(18 + std::mem::size_of::<AxisRecord>() as u32));
        assert_eq!(buf.len(), 18, "sanity check");
        // now push one axis record:
        buf.push(Tag::new(b"wght"));
        buf.extend([1u16, 1u16]);
        // and two value tables:

        //let axis_value_offset_start = buf.len();
        buf.push(4u16); // first offset
        buf.push(4u16 + std::mem::size_of::<AxisValueFormat1>() as u16); // first offset

        // format 1:
        buf.push(1u16);
        buf.push(9u16);
        buf.push(0u16);
        buf.push(2u16);
        buf.push(Fixed::from_f64(42.0));

        // format 3:
        buf.push(3u16);
        buf.push(0u16);
        buf.push(0u16);
        buf.push(7u16);
        buf.push(Fixed::from_f64(-3.3));
        buf.push(Fixed::from_f64(108.));

        let table = Stat::read(&buf).unwrap();
        assert_eq!(table.design_axis_count(), 1);
        assert_eq!(table.design_axis_count(), 1);
        assert_eq!(table.elided_fallback_name_id(), None);

        let values = table.iter_axis_value_tables().collect::<Vec<_>>();
        let value1 = match values[0] {
            AxisValue::Format1(table) => table,
            AxisValue::Format2(_) => panic!("format2"),
            AxisValue::Format3(_) => panic!("format3"),
            AxisValue::Format4(_) => panic!("format4"),
        };

        assert_eq!(value1.axis_index(), 9);
        assert_eq!(value1.value(), Fixed::from_f64(42.0));
        let value2 = match values[1] {
            AxisValue::Format3(table) => table,
            _ => panic!("unexpected format"),
        };

        assert_eq!(value2.value_name_id(), 7);
        assert_eq!(value2.linked_value(), Fixed::from_f64(108.));
    }
}
<commit_msg>Use AxisValueFlags type in STAT table<commit_after>//! the [STAT] table
//!
//! [STAT]: https://docs.microsoft.com/en-us/typography/opentype/spec/stat

use font_types::{
    BigEndian, Fixed, FontRead, MajorMinor, Offset, Offset16, Offset32, OffsetHost, Tag,
};
use zerocopy::LayoutVerified;

/// 'STAT'
pub const TAG: Tag = Tag::new(b"STAT");

font_types::tables! {
    /// [STAT](https://docs.microsoft.com/en-us/typography/opentype/spec/stat) (Style Attributes Table)
    #[offset_host]
    Stat1_0<'a> {
        /// Major version number of the style attributes table — set to 1.
        major_version: BigEndian<u16>,
        /// Minor version number of the style attributes table — set to 2.
        minor_version: BigEndian<u16>,
        /// The size in bytes of each axis record.
        design_axis_size: BigEndian<u16>,
        /// The number of axis records. In a font with an 'fvar' table,
        /// this value must be greater than or equal to the axisCount value
        /// in the 'fvar' table. In all fonts, must be greater than zero if
        /// axisValueCount is greater than zero.
        design_axis_count: BigEndian<u16>,
        /// Offset in bytes from the beginning of the STAT table to the
        /// start of the design axes array. If designAxisCount is zero, set
        /// to zero; if designAxisCount is greater than zero, must be
        /// greater than zero.
        design_axes_offset: BigEndian<Offset32>,
        /// The number of axis value tables.
        axis_value_count: BigEndian<u16>,
        /// Offset in bytes from the beginning of the STAT table to the
        /// start of the design axes value offsets array. If axisValueCount
        /// is zero, set to zero; if axisValueCount is greater than zero,
        /// must be greater than zero.
        offset_to_axis_value_offsets: BigEndian<Offset32>,
    }

    /// [STAT](https://docs.microsoft.com/en-us/typography/opentype/spec/stat) (Style Attributes Table)
    #[offset_host]
    Stat1_2<'a> {
        /// Major version number of the style attributes table — set to 1.
        major_version: BigEndian<u16>,
        /// Minor version number of the style attributes table — set to 2.
        minor_version: BigEndian<u16>,
        /// The size in bytes of each axis record.
        design_axis_size: BigEndian<u16>,
        /// The number of axis records. In a font with an 'fvar' table,
        /// this value must be greater than or equal to the axisCount value
        /// in the 'fvar' table. In all fonts, must be greater than zero if
        /// axisValueCount is greater than zero.
        design_axis_count: BigEndian<u16>,
        /// Offset in bytes from the beginning of the STAT table to the
        /// start of the design axes array. If designAxisCount is zero, set
        /// to zero; if designAxisCount is greater than zero, must be
        /// greater than zero.
        design_axes_offset: BigEndian<Offset32>,
        /// The number of axis value tables.
        axis_value_count: BigEndian<u16>,
        /// Offset in bytes from the beginning of the STAT table to the
        /// start of the design axes value offsets array. If axisValueCount
        /// is zero, set to zero; if axisValueCount is greater than zero,
        /// must be greater than zero.
        offset_to_axis_value_offsets: BigEndian<Offset32>,
        /// Name ID used as fallback when projection of names into a
        /// particular font model produces a subfamily name containing only
        /// elidable elements.
        elided_fallback_name_id: BigEndian<u16>,
    }

    /// [Axis Records](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-records)
    AxisRecord {
        /// A tag identifying the axis of design variation.
        axis_tag: BigEndian<Tag>,
        /// The name ID for entries in the 'name' table that provide a
        /// display string for this axis.
        axis_name_id: BigEndian<u16>,
        /// A value that applications can use to determine primary sorting
        /// of face names, or for ordering of labels when composing family
        /// or face names.
        axis_ordering: BigEndian<u16>,
    }

    /// [STAT](https://docs.microsoft.com/en-us/typography/opentype/spec/stat) (Style Attributes Table)
    #[format(MajorMinor)]
    #[generate_getters]
    enum Stat<'a> {
        #[version(MajorMinor::VERSION_1_0)]
        Version1_0(Stat1_0<'a>),
        #[version(MajorMinor::VERSION_1_2)]
        Version1_2(Stat1_2<'a>),
    }
}

//FIXME: we should generate this automatically?
impl<'a> OffsetHost<'a> for Stat<'a> {
    fn bytes(&self) -> &'a [u8] {
        match self {
            Stat::Version1_0(table) => table.bytes(),
            Stat::Version1_2(table) => table.bytes(),
        }
    }
}

impl<'a> Stat<'a> {
    /// The design-axes array.
    pub fn design_axes(&self) -> impl Iterator<Item = AxisRecord> + '_ {
        let count = self.design_axis_count();
        let offset = self.design_axes_offset();
        let record_len = self.design_axis_size() as usize;
        let bytes = self.bytes_at_offset(offset);
        let mut idx = 0;
        std::iter::from_fn(move || {
            if idx == count as usize {
                return None;
            }
            let rel_off = idx * record_len;
            let result = bytes
                .get(rel_off..rel_off + record_len)
                .and_then(AxisRecord::read);
            idx += 1;
            result
        })
    }

    fn axis_value_offsets(&self) -> &[BigEndian<Offset16>] {
        let count = self.axis_value_count();
        let offset = self.offset_to_axis_value_offsets();
        let bytes = self.bytes_at_offset(offset);
        match LayoutVerified::new_slice_unaligned_from_prefix(bytes, count as usize) {
            Some((layout, _)) => layout.into_slice(),
            None => &[],
        }
    }

    pub fn iter_axis_value_tables(&self) -> impl Iterator<Item = AxisValue<'a>> + '_ {
        let offset_start = self.offset_to_axis_value_offsets();
        let bytes = self.bytes_at_offset(offset_start);
        self.axis_value_offsets().iter().map_while(|off| {
            off.get()
                .non_null()
                .and_then(|off| bytes.get(off..).and_then(AxisValue::read))
        })
    }
}

font_types::tables! {

    /// [Axis Value Tables](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-tables)
    #[format(u16)]
    enum AxisValue<'a> {
        #[version(1)]
        Format1(AxisValueFormat1),
        #[version(2)]
        Format2(AxisValueFormat2),
        #[version(3)]
        Format3(AxisValueFormat3),
        #[version(4)]
        Format4(AxisValueFormat4<'a>),
    }

    /// [Axis value table format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-1)
    AxisValueFormat1 {
        /// Format identifier — set to 1.
        format: BigEndian<u16>,
        /// Zero-base index into the axis record array identifying the axis
        /// of design variation to which the axis value table applies. Must
        /// be less than designAxisCount.
        axis_index: BigEndian<u16>,
        /// Flags — see below for details.
        flags: BigEndian<AxisValueFlags>,
        /// The name ID for entries in the 'name' table that provide a
        /// display string for this attribute value.
        value_name_id: BigEndian<u16>,
        /// A numeric value for this attribute value.
        value: BigEndian<Fixed>,
    }

    /// [Axis value table format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-2)
    AxisValueFormat2 {
        /// Format identifier — set to 2.
        format: BigEndian<u16>,
        /// Zero-base index into the axis record array identifying the axis
        /// of design variation to which the axis value table applies. Must
        /// be less than designAxisCount.
        axis_index: BigEndian<u16>,
        /// Flags — see below for details.
        flags: BigEndian<AxisValueFlags>,
        /// The name ID for entries in the 'name' table that provide a
        /// display string for this attribute value.
        value_name_id: BigEndian<u16>,
        /// A nominal numeric value for this attribute value.
        nominal_value: BigEndian<Fixed>,
        /// The minimum value for a range associated with the specified
        /// name ID.
        range_min_value: BigEndian<Fixed>,
        /// The maximum value for a range associated with the specified
        /// name ID.
        range_max_value: BigEndian<Fixed>,
    }

    /// [Axis value table format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-3)
    AxisValueFormat3 {
        /// Format identifier — set to 3.
        format: BigEndian<u16>,
        /// Zero-base index into the axis record array identifying the axis
        /// of design variation to which the axis value table applies. Must
        /// be less than designAxisCount.
        axis_index: BigEndian<u16>,
        /// Flags — see below for details.
        flags: BigEndian<AxisValueFlags>,
        /// The name ID for entries in the 'name' table that provide a
        /// display string for this attribute value.
        value_name_id: BigEndian<u16>,
        /// A numeric value for this attribute value.
        value: BigEndian<Fixed>,
        /// The numeric value for a style-linked mapping from this value.
        linked_value: BigEndian<Fixed>,
    }

    /// [Axis value table format 4](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-4)
    AxisValueFormat4<'a> {
        /// Format identifier — set to 4.
        format: BigEndian<u16>,
        /// The total number of axes contributing to this axis-values
        /// combination.
        axis_count: BigEndian<u16>,
        /// Flags — see below for details.
        flags: BigEndian<AxisValueFlags>,
        /// The name ID for entries in the 'name' table that provide a
        /// display string for this combination of axis values.
        value_name_id: BigEndian<u16>,
        /// Array of AxisValue records that provide the combination of axis
        /// values, one for each contributing axis.
        #[count(axis_count)]
        axis_values: [AxisValueRecord],
    }

    /// Part of [AxisValueFormat4]
    AxisValueRecord {
        /// Zero-base index into the axis record array identifying the axis
        /// to which this value applies. Must be less than designAxisCount.
        axis_index: BigEndian<u16>,
        /// A numeric value for this attribute value.
        value: BigEndian<Fixed>,
    }

    /// [Axis value table flags](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#flags).
#[flags(u16)]
    AxisValueFlags {
        /// If set, this axis value table provides axis value information
        /// that is applicable to other fonts within the same font family.
        /// This is used if the other fonts were released earlier and did
        /// not include information about values for some axis. If newer
        /// versions of the other fonts include the information themselves
        /// and are present, then this table is ignored.
        OLDER_SIBLING_FONT_ATTRIBUTE = 0x0001,
        /// If set, it indicates that the axis value represents the
        /// “normal” value for the axis and may be omitted when
        /// composing name strings.
        ELIDABLE_AXIS_VALUE_NAME = 0x0002,
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn smoke_test() {
        let mut buf = font_types::test_helpers::BeBuffer::new();
        buf.extend([1u16, 0]); // version
        buf.push(std::mem::size_of::<AxisRecord>() as u16); // design axis size
        buf.push(1u16); // design axis count
        buf.push(Offset32::new(18));
        buf.push(2u16);
        buf.push(Offset32::new(18 + std::mem::size_of::<AxisRecord>() as u32));
        assert_eq!(buf.len(), 18, "sanity check");
        // now push one axis record:
        buf.push(Tag::new(b"wght"));
        buf.extend([1u16, 1u16]);
        // and two value tables:

        //let axis_value_offset_start = buf.len();
        buf.push(4u16); // first offset
        buf.push(4u16 + std::mem::size_of::<AxisValueFormat1>() as u16); // first offset

        // format 1:
        buf.push(1u16);
        buf.push(9u16);
        buf.push(0u16);
        buf.push(2u16);
        buf.push(Fixed::from_f64(42.0));

        // format 3:
        buf.push(3u16);
        buf.push(0u16);
        buf.push(0u16);
        buf.push(7u16);
        buf.push(Fixed::from_f64(-3.3));
        buf.push(Fixed::from_f64(108.));

        let table = Stat::read(&buf).unwrap();
        assert_eq!(table.design_axis_count(), 1);
        assert_eq!(table.design_axis_count(), 1);
        assert_eq!(table.elided_fallback_name_id(), None);

        let values = table.iter_axis_value_tables().collect::<Vec<_>>();
        let value1 = match values[0] {
            AxisValue::Format1(table) => table,
            AxisValue::Format2(_) => panic!("format2"),
            AxisValue::Format3(_) => panic!("format3"),
            AxisValue::Format4(_) => panic!("format4"),
        };

        assert_eq!(value1.axis_index(), 9);
        assert_eq!(value1.value(), Fixed::from_f64(42.0));
        let value2 = match values[1] {
            AxisValue::Format3(table) => table,
            _ => panic!("unexpected format"),
        };

        assert_eq!(value2.value_name_id(), 7);
        assert_eq!(value2.linked_value(), Fixed::from_f64(108.));
    }
}
<|endoftext|>


<commit_before>extern crate birl;

use std::env::args;
use birl::context::Context;

fn start_interactive_console() {
	/* Print heading info. */
	eprintln!("O SHELL QUE CONSTRÓI FIBRA. VERSÃO {}", env!("CARGO_PKG_VERSION"));
	eprintln!("BIRL  © 2018, RAFAEL RODRIGUES NAKANO.");
	eprintln!("SHELL © 2018, MATHEUS BRANCO BORELLA.");
	eprintln!();

	/* Setup BIRL.
	 * The Context interpreter is not built to run interactively,
	 * by default, as it lacks much of the framework that would be
	 * needed to properly implement an interactive shell with
	 * immidiate evaluation of expresssions.
	 *
	 * So, as a workaround, the shell cycles the interpreter manually
	 * to the completion of all instructions added by a line. To
	 * achieve that, we first call the root function, as any
	 * expression typed into the interpreted will be compiled as a
	 * root-level instruction.
	 */
	use birl::context::Context;
	let mut c = Context::new();

	use birl::context::BIRL_GLOBAL_FUNCTION_ID;
	c.call_function_by_id(BIRL_GLOBAL_FUNCTION_ID, vec![])
		.expect("Could not setup BIRL runtime.");

	/* Bind the Context interpreter to standard IO */
	let _ = c.set_stdin({
		use std::io;
		let reader = io::BufReader::new(io::stdin());
		Some(Box::new(reader))
	});
	let _ = c.set_stdout({
		use std::io;
		Some(Box::new(io::stdout()))
	});

	/* Enter interactive loop */
	use std::io::{stdin, BufReader, BufRead};
	let mut prompt = BufReader::new(stdin());
	loop{
		eprint!("> ");

		let mut line = String::new();
		match prompt.read_line(&mut line){
			Ok(count) => if count == 0 {
				eprintln!("Reached end of input.");
				break
			},
			Err(what) => {
				eprintln!("A read error occured: {:?}", what);
				break
			}
		}

		/* Parse and evaluate */
		if let Err(what) = c.process_line(&line){
			eprintln!("{}", what);
		} else {
			/* Drives the currently pending instructions to
			 * completion. */
			let mut saturate = || loop{
				let status = c.execute_next_instruction();

				use birl::vm::ExecutionStatus as Es;
				match status{
					Ok(Es::Quit) => break Ok(()),
					Err(what)    => break Err(what),
					_ => {}
				}
			};

			if let Err(what) = saturate(){
				eprintln!("{}", what);
			}
		}
	}

	/* Make sure the output is flushed */
	c.set_stdout(None).unwrap().flush()
		.expect("Could not flush io::stdout().");
}

fn print_help() {
	Context::print_version();

	println!("Ta querendo ajuda, cumpade?");
	println!("O uso é o seguinte: birl [opções] [arquivo ou arquivos]");
	println!("Cê pode passar mais de um arquivo, só que apenas um pode ter a seção \"SHOW\", que \
              é o ponto de partida do teu programa.");
	println!("As opções são as seguintes:");
	println!("\t-a ou --ajuda-o-maluco-ta-doente\t: Imprime essa mensagem de ajuda");
	println!("\t-v ou --versao\t\t\t\t: Imprime a versão do programa");
	println!("\t-s ou --string \"[codigo]\"\t\t: Executa o codigo na string ao inves de \
              um arquivo.");
	println!("\t-i ou --interativo\t\t\t\t: Inicia um console interativo pra rodar códigos");
}

/// Parameters passed through the command line
enum Param {
	PrintVersion,
	PrintHelp,
	/// Add a file to be processed
	InputFile(String),
	/// Processes code from a given string
	StringSource(String),
	/// Starts an interactive console for running code
	Interactive,
}

fn get_params() -> Vec<Param> {
	let mut arguments = args();
	let mut result: Vec<Param> = vec![];

	let _ = arguments.next().unwrap(); // Dispose of the first argument

	loop {
		if let Some(arg) = arguments.next() {
			match arg.as_str() {
				"-a" | "--ajuda-o-maluco-ta-doente" => result.push(Param::PrintHelp),
				"-v" | "--versao-cumpade" => result.push(Param::PrintVersion),
				"-i" | "--interativo" => result.push(Param::Interactive),
				"-s" | "--string" => {
					// The next argument is expected to be a string containing source code
					if let Some(code) = arguments.next() {
						result.push(Param::StringSource(code));
					} else {
						println!("Erro: O argumento {} precisa de um conteúdo logo em seguida, bixo.", arg);
					}
				}
				// Push the file to the result stack
				_ => result.push(Param::InputFile(arg))
			}
		} else {
			break;
		}
	}

	result
}

fn main() {
	let args = get_params();
	let mut interactive = false;

	let mut ctx = Context::new();

	if args.len() > 0 {
		for arg in args {
			match arg {
				Param::PrintHelp => print_help(),
				Param::Interactive => interactive = true,
				Param::PrintVersion => Context::print_version(),
				Param::InputFile(file) => {
					match ctx.add_file(file.as_str()) {
						Ok(_) => {}
						Err(e) => {
							println!("Ocorreu um erro ao adicionar o arquivo \"{}\" pro contexto : {}",
									 file.as_str(), e);
							// Exit? continue?
						}
					}
				}
				Param::StringSource(source) => {
					match ctx.add_source_string(source) {
						Ok(_) => {}
						Err(e) => {
							println!("Erro ao adicionar string de código ao contexto : {}", e);
						}
					}
				}
			}
		}
	} else {
		interactive = true;
	}

	if interactive {
		start_interactive_console();
	} else {
        /* Bind the Context interpreter to standard IO */
        let _ = ctx.set_stdin({
            use std::io;
            let reader = io::BufReader::new(io::stdin());
            Some(Box::new(reader))
        });
        let _ = ctx.set_stdout({
            use std::io;
            Some(Box::new(io::stdout()))
        });

		match ctx.start_program() {
			Ok(_) => {}
			Err(e) => println!("Erro de execução : {}", e),
		}
	}
}<commit_msg>Shell ajustado por causas das mudanças na lib<commit_after>extern crate birl;

use std::env::args;
use birl::context::Context;

fn start_interactive_console() {
	/* Print heading info. */
	eprintln!("O SHELL QUE CONSTRÓI FIBRA. VERSÃO {}", birl::context::BIRL_VERSION);
	eprintln!("BIRL  © 2018, RAFAEL RODRIGUES NAKANO.");
	eprintln!("SHELL © 2018, MATHEUS BRANCO BORELLA.");
	eprintln!();

	/* Setup BIRL.
	 * The Context interpreter is not built to run interactively,
	 * by default, as it lacks much of the framework that would be
	 * needed to properly implement an interactive shell with
	 * immidiate evaluation of expresssions.
	 *
	 * So, as a workaround, the shell cycles the interpreter manually
	 * to the completion of all instructions added by a line. To
	 * achieve that, we first call the root function, as any
	 * expression typed into the interpreted will be compiled as a
	 * root-level instruction.
	 */
	use birl::context::Context;
	let mut c = Context::new();

    c.set_interactive_mode();

	use birl::context::BIRL_GLOBAL_FUNCTION_ID;
	c.call_function_by_id(BIRL_GLOBAL_FUNCTION_ID, vec![])
		.expect("Could not setup BIRL runtime.");

	/* Bind the Context interpreter to standard IO */
	let _ = c.set_stdin({
		use std::io;
		let reader = io::BufReader::new(io::stdin());
		Some(Box::new(reader))
	});
	let _ = c.set_stdout({
		use std::io;
		Some(Box::new(io::stdout()))
	});

	/* Enter interactive loop */
	use std::io::{stdin, BufReader, BufRead};
	let mut prompt = BufReader::new(stdin());
	loop{
		eprint!("> ");

		let mut line = String::new();
		match prompt.read_line(&mut line){
			Ok(count) => if count == 0 {
				eprintln!("Reached end of input.");
				break
			},
			Err(what) => {
				eprintln!("A read error occured: {:?}", what);
				break
			}
		}

		/* Parse and evaluate */
		if let Err(what) = c.process_line(&line){
			eprintln!("{}", what);
		} else {
			/* Drives the currently pending instructions to
			 * completion. */

            use birl::vm::ExecutionStatus as Es;
            loop {
                match c.execute_next_instruction() {
                    Ok(Es::Quit) => {
                        eprintln!("Saindo...");
                        return;
                    }
                    Ok(Es::Halt) => break,
                    Ok(_) => {}
                    Err(e) => {
                        eprintln!("{}", e);
                    }
                }
            }
		}
	}

	/* Make sure the output is flushed */
	c.set_stdout(None).unwrap().flush()
		.expect("Could not flush io::stdout().");
}

fn print_help() {
	Context::print_version();

	println!("Ta querendo ajuda, cumpade?");
	println!("O uso é o seguinte: birl [opções] [arquivo ou arquivos]");
	println!("Cê pode passar mais de um arquivo, só que apenas um pode ter a seção \"SHOW\", que \
              é o ponto de partida do teu programa.");
	println!("As opções são as seguintes:");
	println!("\t-a ou --ajuda-o-maluco-ta-doente\t: Imprime essa mensagem de ajuda");
	println!("\t-v ou --versao\t\t\t\t: Imprime a versão do programa");
	println!("\t-s ou --string \"[codigo]\"\t\t: Executa o codigo na string ao inves de \
              um arquivo.");
	println!("\t-i ou --interativo\t\t\t\t: Inicia um console interativo pra rodar códigos");
}

/// Parameters passed through the command line
enum Param {
	PrintVersion,
	PrintHelp,
	/// Add a file to be processed
	InputFile(String),
	/// Processes code from a given string
	StringSource(String),
	/// Starts an interactive console for running code
	Interactive,
}

fn get_params() -> Vec<Param> {
	let mut arguments = args();
	let mut result: Vec<Param> = vec![];

	let _ = arguments.next().unwrap(); // Dispose of the first argument

	loop {
		if let Some(arg) = arguments.next() {
			match arg.as_str() {
				"-a" | "--ajuda-o-maluco-ta-doente" => result.push(Param::PrintHelp),
				"-v" | "--versao-cumpade" => result.push(Param::PrintVersion),
				"-i" | "--interativo" => result.push(Param::Interactive),
				"-s" | "--string" => {
					// The next argument is expected to be a string containing source code
					if let Some(code) = arguments.next() {
						result.push(Param::StringSource(code));
					} else {
						println!("Erro: O argumento {} precisa de um conteúdo logo em seguida, bixo.", arg);
					}
				}
				// Push the file to the result stack
				_ => result.push(Param::InputFile(arg))
			}
		} else {
			break;
		}
	}

	result
}

fn main() {
	let args = get_params();
	let mut interactive = false;

	let mut ctx = Context::new();

	if args.len() > 0 {
		for arg in args {
			match arg {
				Param::PrintHelp => print_help(),
				Param::Interactive => interactive = true,
				Param::PrintVersion => Context::print_version(),
				Param::InputFile(file) => {
					match ctx.add_file(file.as_str()) {
						Ok(_) => {}
						Err(e) => {
							println!("Ocorreu um erro ao adicionar o arquivo \"{}\" pro contexto : {}",
									 file.as_str(), e);
							// Exit? continue?
						}
					}
				}
				Param::StringSource(source) => {
					match ctx.add_source_string(source) {
						Ok(_) => {}
						Err(e) => {
							println!("Erro ao adicionar string de código ao contexto : {}", e);
						}
					}
				}
			}
		}
	} else {
		interactive = true;
	}

	if interactive {
		start_interactive_console();
	} else {
        /* Bind the Context interpreter to standard IO */
        let _ = ctx.set_stdin({
            use std::io;
            let reader = io::BufReader::new(io::stdin());
            Some(Box::new(reader))
        });
        let _ = ctx.set_stdout({
            use std::io;
            Some(Box::new(io::stdout()))
        });

		match ctx.start_program() {
			Ok(_) => {}
			Err(e) => println!("Erro de execução : {}", e),
		}
	}
}<|endoftext|>


<commit_before>use crate::codec::framed_impl::{FramedImpl, ReadFrame};
use crate::codec::Decoder;

use tokio::{io::AsyncRead, stream::Stream};

use bytes::BytesMut;
use futures_sink::Sink;
use pin_project_lite::pin_project;
use std::fmt;
use std::pin::Pin;
use std::task::{Context, Poll};

pin_project! {
    /// A [`Stream`] of messages decoded from an [`AsyncRead`].
    ///
    /// [`Stream`]: tokio::stream::Stream
    /// [`AsyncRead`]: tokio::io::AsyncRead
    pub struct FramedRead<T, D> {
        #[pin]
        inner: FramedImpl<T, D, ReadFrame>,
    }
}

// ===== impl FramedRead =====

impl<T, D> FramedRead<T, D>
where
    T: AsyncRead,
    D: Decoder,
{
    /// Creates a new `FramedRead` with the given `decoder`.
    pub fn new(inner: T, decoder: D) -> FramedRead<T, D> {
        FramedRead {
            inner: FramedImpl {
                inner,
                codec: decoder,
                state: Default::default(),
            },
        }
    }

    /// Creates a new `FramedRead` with the given `decoder` and a buffer of `capacity`
    /// initial size.
    pub fn with_capacity(inner: T, decoder: D, capacity: usize) -> FramedRead<T, D> {
        FramedRead {
            inner: FramedImpl {
                inner,
                codec: decoder,
                state: ReadFrame {
                    eof: false,
                    is_readable: false,
                    buffer: BytesMut::with_capacity(capacity),
                },
            },
        }
    }
}

impl<T, D> FramedRead<T, D> {
    /// Returns a reference to the underlying I/O stream wrapped by
    /// `FramedRead`.
    ///
    /// Note that care should be taken to not tamper with the underlying stream
    /// of data coming in as it may corrupt the stream of frames otherwise
    /// being worked with.
    pub fn get_ref(&self) -> &T {
        &self.inner.inner
    }

    /// Returns a mutable reference to the underlying I/O stream wrapped by
    /// `FramedRead`.
    ///
    /// Note that care should be taken to not tamper with the underlying stream
    /// of data coming in as it may corrupt the stream of frames otherwise
    /// being worked with.
    pub fn get_mut(&mut self) -> &mut T {
        &mut self.inner.inner
    }

    /// Consumes the `FramedRead`, returning its underlying I/O stream.
    ///
    /// Note that care should be taken to not tamper with the underlying stream
    /// of data coming in as it may corrupt the stream of frames otherwise
    /// being worked with.
    pub fn into_inner(self) -> T {
        self.inner.inner
    }

    /// Returns a reference to the underlying decoder.
    pub fn decoder(&self) -> &D {
        &self.inner.codec
    }

    /// Returns a mutable reference to the underlying decoder.
    pub fn decoder_mut(&mut self) -> &mut D {
        &mut self.inner.codec
    }

    /// Returns a reference to the read buffer.
    pub fn read_buffer(&self) -> &BytesMut {
        &self.inner.state.buffer
    }
}

// This impl just defers to the underlying FramedImpl
impl<T, D> Stream for FramedRead<T, D>
where
    T: AsyncRead,
    D: Decoder,
{
    type Item = Result<D::Item, D::Error>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        self.project().inner.poll_next(cx)
    }
}

// This impl just defers to the underlying T: Sink
impl<T, I, D> Sink<I> for FramedRead<T, D>
where
    T: Sink<I>,
{
    type Error = T::Error;

    fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.project().inner.project().inner.poll_ready(cx)
    }

    fn start_send(self: Pin<&mut Self>, item: I) -> Result<(), Self::Error> {
        self.project().inner.project().inner.start_send(item)
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.project().inner.project().inner.poll_flush(cx)
    }

    fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.project().inner.project().inner.poll_close(cx)
    }
}

impl<T, D> fmt::Debug for FramedRead<T, D>
where
    T: fmt::Debug,
    D: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("FramedRead")
            .field("inner", &self.get_ref())
            .field("decoder", &self.decoder())
            .field("eof", &self.inner.state.eof)
            .field("is_readable", &self.inner.state.is_readable)
            .field("buffer", &self.read_buffer())
            .finish()
    }
}
<commit_msg>codec: add read_buffer_mut to FramedRead (#3166)<commit_after>use crate::codec::framed_impl::{FramedImpl, ReadFrame};
use crate::codec::Decoder;

use tokio::{io::AsyncRead, stream::Stream};

use bytes::BytesMut;
use futures_sink::Sink;
use pin_project_lite::pin_project;
use std::fmt;
use std::pin::Pin;
use std::task::{Context, Poll};

pin_project! {
    /// A [`Stream`] of messages decoded from an [`AsyncRead`].
    ///
    /// [`Stream`]: tokio::stream::Stream
    /// [`AsyncRead`]: tokio::io::AsyncRead
    pub struct FramedRead<T, D> {
        #[pin]
        inner: FramedImpl<T, D, ReadFrame>,
    }
}

// ===== impl FramedRead =====

impl<T, D> FramedRead<T, D>
where
    T: AsyncRead,
    D: Decoder,
{
    /// Creates a new `FramedRead` with the given `decoder`.
    pub fn new(inner: T, decoder: D) -> FramedRead<T, D> {
        FramedRead {
            inner: FramedImpl {
                inner,
                codec: decoder,
                state: Default::default(),
            },
        }
    }

    /// Creates a new `FramedRead` with the given `decoder` and a buffer of `capacity`
    /// initial size.
    pub fn with_capacity(inner: T, decoder: D, capacity: usize) -> FramedRead<T, D> {
        FramedRead {
            inner: FramedImpl {
                inner,
                codec: decoder,
                state: ReadFrame {
                    eof: false,
                    is_readable: false,
                    buffer: BytesMut::with_capacity(capacity),
                },
            },
        }
    }
}

impl<T, D> FramedRead<T, D> {
    /// Returns a reference to the underlying I/O stream wrapped by
    /// `FramedRead`.
    ///
    /// Note that care should be taken to not tamper with the underlying stream
    /// of data coming in as it may corrupt the stream of frames otherwise
    /// being worked with.
    pub fn get_ref(&self) -> &T {
        &self.inner.inner
    }

    /// Returns a mutable reference to the underlying I/O stream wrapped by
    /// `FramedRead`.
    ///
    /// Note that care should be taken to not tamper with the underlying stream
    /// of data coming in as it may corrupt the stream of frames otherwise
    /// being worked with.
    pub fn get_mut(&mut self) -> &mut T {
        &mut self.inner.inner
    }

    /// Consumes the `FramedRead`, returning its underlying I/O stream.
    ///
    /// Note that care should be taken to not tamper with the underlying stream
    /// of data coming in as it may corrupt the stream of frames otherwise
    /// being worked with.
    pub fn into_inner(self) -> T {
        self.inner.inner
    }

    /// Returns a reference to the underlying decoder.
    pub fn decoder(&self) -> &D {
        &self.inner.codec
    }

    /// Returns a mutable reference to the underlying decoder.
    pub fn decoder_mut(&mut self) -> &mut D {
        &mut self.inner.codec
    }

    /// Returns a reference to the read buffer.
    pub fn read_buffer(&self) -> &BytesMut {
        &self.inner.state.buffer
    }

    /// Returns a mutable reference to the read buffer.
    pub fn read_buffer_mut(&mut self) -> &mut BytesMut {
        &mut self.inner.state.buffer
    }
}

// This impl just defers to the underlying FramedImpl
impl<T, D> Stream for FramedRead<T, D>
where
    T: AsyncRead,
    D: Decoder,
{
    type Item = Result<D::Item, D::Error>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        self.project().inner.poll_next(cx)
    }
}

// This impl just defers to the underlying T: Sink
impl<T, I, D> Sink<I> for FramedRead<T, D>
where
    T: Sink<I>,
{
    type Error = T::Error;

    fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.project().inner.project().inner.poll_ready(cx)
    }

    fn start_send(self: Pin<&mut Self>, item: I) -> Result<(), Self::Error> {
        self.project().inner.project().inner.start_send(item)
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.project().inner.project().inner.poll_flush(cx)
    }

    fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.project().inner.project().inner.poll_close(cx)
    }
}

impl<T, D> fmt::Debug for FramedRead<T, D>
where
    T: fmt::Debug,
    D: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("FramedRead")
            .field("inner", &self.get_ref())
            .field("decoder", &self.decoder())
            .field("eof", &self.inner.state.eof)
            .field("is_readable", &self.inner.state.is_readable)
            .field("buffer", &self.read_buffer())
            .finish()
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(any(loom, not(feature = "sync")), allow(dead_code, unreachable_pub))]

use crate::loom::cell::UnsafeCell;
use crate::loom::sync::atomic::{self, AtomicUsize};

use std::fmt;
use std::sync::atomic::Ordering::{AcqRel, Acquire, Release};
use std::task::Waker;

/// A synchronization primitive for task waking.
///
/// `AtomicWaker` will coordinate concurrent wakes with the consumer
/// potentially "waking" the underlying task. This is useful in scenarios
/// where a computation completes in another thread and wants to wake the
/// consumer, but the consumer is in the process of being migrated to a new
/// logical task.
///
/// Consumers should call `register` before checking the result of a computation
/// and producers should call `wake` after producing the computation (this
/// differs from the usual `thread::park` pattern). It is also permitted for
/// `wake` to be called **before** `register`. This results in a no-op.
///
/// A single `AtomicWaker` may be reused for any number of calls to `register` or
/// `wake`.
pub(crate) struct AtomicWaker {
    state: AtomicUsize,
    waker: UnsafeCell<Option<Waker>>,
}

// `AtomicWaker` is a multi-consumer, single-producer transfer cell. The cell
// stores a `Waker` value produced by calls to `register` and many threads can
// race to take the waker by calling `wake.
//
// If a new `Waker` instance is produced by calling `register` before an existing
// one is consumed, then the existing one is overwritten.
//
// While `AtomicWaker` is single-producer, the implementation ensures memory
// safety. In the event of concurrent calls to `register`, there will be a
// single winner whose waker will get stored in the cell. The losers will not
// have their tasks woken. As such, callers should ensure to add synchronization
// to calls to `register`.
//
// The implementation uses a single `AtomicUsize` value to coordinate access to
// the `Waker` cell. There are two bits that are operated on independently. These
// are represented by `REGISTERING` and `WAKING`.
//
// The `REGISTERING` bit is set when a producer enters the critical section. The
// `WAKING` bit is set when a consumer enters the critical section. Neither
// bit being set is represented by `WAITING`.
//
// A thread obtains an exclusive lock on the waker cell by transitioning the
// state from `WAITING` to `REGISTERING` or `WAKING`, depending on the
// operation the thread wishes to perform. When this transition is made, it is
// guaranteed that no other thread will access the waker cell.
//
// # Registering
//
// On a call to `register`, an attempt to transition the state from WAITING to
// REGISTERING is made. On success, the caller obtains a lock on the waker cell.
//
// If the lock is obtained, then the thread sets the waker cell to the waker
// provided as an argument. Then it attempts to transition the state back from
// `REGISTERING` -> `WAITING`.
//
// If this transition is successful, then the registering process is complete
// and the next call to `wake` will observe the waker.
//
// If the transition fails, then there was a concurrent call to `wake` that
// was unable to access the waker cell (due to the registering thread holding the
// lock). To handle this, the registering thread removes the waker it just set
// from the cell and calls `wake` on it. This call to wake represents the
// attempt to wake by the other thread (that set the `WAKING` bit). The
// state is then transitioned from `REGISTERING | WAKING` back to `WAITING`.
// This transition must succeed because, at this point, the state cannot be
// transitioned by another thread.
//
// # Waking
//
// On a call to `wake`, an attempt to transition the state from `WAITING` to
// `WAKING` is made. On success, the caller obtains a lock on the waker cell.
//
// If the lock is obtained, then the thread takes ownership of the current value
// in the waker cell, and calls `wake` on it. The state is then transitioned
// back to `WAITING`. This transition must succeed as, at this point, the state
// cannot be transitioned by another thread.
//
// If the thread is unable to obtain the lock, the `WAKING` bit is still.
// This is because it has either been set by the current thread but the previous
// value included the `REGISTERING` bit **or** a concurrent thread is in the
// `WAKING` critical section. Either way, no action must be taken.
//
// If the current thread is the only concurrent call to `wake` and another
// thread is in the `register` critical section, when the other thread **exits**
// the `register` critical section, it will observe the `WAKING` bit and
// handle the waker itself.
//
// If another thread is in the `waker` critical section, then it will handle
// waking the caller task.
//
// # A potential race (is safely handled).
//
// Imagine the following situation:
//
// * Thread A obtains the `wake` lock and wakes a task.
//
// * Before thread A releases the `wake` lock, the woken task is scheduled.
//
// * Thread B attempts to wake the task. In theory this should result in the
//   task being woken, but it cannot because thread A still holds the wake
//   lock.
//
// This case is handled by requiring users of `AtomicWaker` to call `register`
// **before** attempting to observe the application state change that resulted
// in the task being woken. The wakers also change the application state
// before calling wake.
//
// Because of this, the task will do one of two things.
//
// 1) Observe the application state change that Thread B is waking on. In
//    this case, it is OK for Thread B's wake to be lost.
//
// 2) Call register before attempting to observe the application state. Since
//    Thread A still holds the `wake` lock, the call to `register` will result
//    in the task waking itself and get scheduled again.

/// Idle state
const WAITING: usize = 0;

/// A new waker value is being registered with the `AtomicWaker` cell.
const REGISTERING: usize = 0b01;

/// The task currently registered with the `AtomicWaker` cell is being woken.
const WAKING: usize = 0b10;

impl AtomicWaker {
    /// Create an `AtomicWaker`
    pub(crate) fn new() -> AtomicWaker {
        AtomicWaker {
            state: AtomicUsize::new(WAITING),
            waker: UnsafeCell::new(None),
        }
    }

    /*
    /// Registers the current waker to be notified on calls to `wake`.
    pub(crate) fn register(&self, waker: Waker) {
        self.do_register(waker);
    }
    */

    /// Registers the provided waker to be notified on calls to `wake`.
    ///
    /// The new waker will take place of any previous wakers that were registered
    /// by previous calls to `register`. Any calls to `wake` that happen after
    /// a call to `register` (as defined by the memory ordering rules), will
    /// wake the `register` caller's task.
    ///
    /// It is safe to call `register` with multiple other threads concurrently
    /// calling `wake`. This will result in the `register` caller's current
    /// task being woken once.
    ///
    /// This function is safe to call concurrently, but this is generally a bad
    /// idea. Concurrent calls to `register` will attempt to register different
    /// tasks to be woken. One of the callers will win and have its task set,
    /// but there is no guarantee as to which caller will succeed.
    pub(crate) fn register_by_ref(&self, waker: &Waker) {
        self.do_register(waker);
    }

    fn do_register<W>(&self, waker: W)
    where
        W: WakerRef,
    {
        match self
            .state
            .compare_exchange(WAITING, REGISTERING, Acquire, Acquire)
            .unwrap_or_else(|x| x)
        {
            WAITING => {
                unsafe {
                    // Locked acquired, update the waker cell
                    self.waker.with_mut(|t| *t = Some(waker.into_waker()));

                    // Release the lock. If the state transitioned to include
                    // the `WAKING` bit, this means that a wake has been
                    // called concurrently, so we have to remove the waker and
                    // wake it.`
                    //
                    // Start by assuming that the state is `REGISTERING` as this
                    // is what we jut set it to.
                    let res = self
                        .state
                        .compare_exchange(REGISTERING, WAITING, AcqRel, Acquire);

                    match res {
                        Ok(_) => {}
                        Err(actual) => {
                            // This branch can only be reached if a
                            // concurrent thread called `wake`. In this
                            // case, `actual` **must** be `REGISTERING |
                            // `WAKING`.
                            debug_assert_eq!(actual, REGISTERING | WAKING);

                            // Take the waker to wake once the atomic operation has
                            // completed.
                            let waker = self.waker.with_mut(|t| (*t).take()).unwrap();

                            // Just swap, because no one could change state
                            // while state == `Registering | `Waking`
                            self.state.swap(WAITING, AcqRel);

                            // The atomic swap was complete, now
                            // wake the waker and return.
                            waker.wake();
                        }
                    }
                }
            }
            WAKING => {
                // Currently in the process of waking the task, i.e.,
                // `wake` is currently being called on the old waker.
                // So, we call wake on the new waker.
                waker.wake();

                // This is equivalent to a spin lock, so use a spin hint.
                // TODO: once we bump MSRV to 1.49+, use `hint::spin_loop` instead.
                #[allow(deprecated)]
                atomic::spin_loop_hint();
            }
            state => {
                // In this case, a concurrent thread is holding the
                // "registering" lock. This probably indicates a bug in the
                // caller's code as racing to call `register` doesn't make much
                // sense.
                //
                // We just want to maintain memory safety. It is ok to drop the
                // call to `register`.
                debug_assert!(state == REGISTERING || state == REGISTERING | WAKING);
            }
        }
    }

    /// Wakes the task that last called `register`.
    ///
    /// If `register` has not been called yet, then this does nothing.
    pub(crate) fn wake(&self) {
        if let Some(waker) = self.take_waker() {
            waker.wake();
        }
    }

    /// Attempts to take the `Waker` value out of the `AtomicWaker` with the
    /// intention that the caller will wake the task later.
    pub(crate) fn take_waker(&self) -> Option<Waker> {
        // AcqRel ordering is used in order to acquire the value of the `waker`
        // cell as well as to establish a `release` ordering with whatever
        // memory the `AtomicWaker` is associated with.
        match self.state.fetch_or(WAKING, AcqRel) {
            WAITING => {
                // The waking lock has been acquired.
                let waker = unsafe { self.waker.with_mut(|t| (*t).take()) };

                // Release the lock
                self.state.fetch_and(!WAKING, Release);

                waker
            }
            state => {
                // There is a concurrent thread currently updating the
                // associated waker.
                //
                // Nothing more to do as the `WAKING` bit has been set. It
                // doesn't matter if there are concurrent registering threads or
                // not.
                //
                debug_assert!(
                    state == REGISTERING || state == REGISTERING | WAKING || state == WAKING
                );
                None
            }
        }
    }
}

impl Default for AtomicWaker {
    fn default() -> Self {
        AtomicWaker::new()
    }
}

impl fmt::Debug for AtomicWaker {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(fmt, "AtomicWaker")
    }
}

unsafe impl Send for AtomicWaker {}
unsafe impl Sync for AtomicWaker {}

trait WakerRef {
    fn wake(self);
    fn into_waker(self) -> Waker;
}

impl WakerRef for Waker {
    fn wake(self) {
        self.wake()
    }

    fn into_waker(self) -> Waker {
        self
    }
}

impl WakerRef for &Waker {
    fn wake(self) {
        self.wake_by_ref()
    }

    fn into_waker(self) -> Waker {
        self.clone()
    }
}
<commit_msg>doc: add missing backtick (#3799)<commit_after>#![cfg_attr(any(loom, not(feature = "sync")), allow(dead_code, unreachable_pub))]

use crate::loom::cell::UnsafeCell;
use crate::loom::sync::atomic::{self, AtomicUsize};

use std::fmt;
use std::sync::atomic::Ordering::{AcqRel, Acquire, Release};
use std::task::Waker;

/// A synchronization primitive for task waking.
///
/// `AtomicWaker` will coordinate concurrent wakes with the consumer
/// potentially "waking" the underlying task. This is useful in scenarios
/// where a computation completes in another thread and wants to wake the
/// consumer, but the consumer is in the process of being migrated to a new
/// logical task.
///
/// Consumers should call `register` before checking the result of a computation
/// and producers should call `wake` after producing the computation (this
/// differs from the usual `thread::park` pattern). It is also permitted for
/// `wake` to be called **before** `register`. This results in a no-op.
///
/// A single `AtomicWaker` may be reused for any number of calls to `register` or
/// `wake`.
pub(crate) struct AtomicWaker {
    state: AtomicUsize,
    waker: UnsafeCell<Option<Waker>>,
}

// `AtomicWaker` is a multi-consumer, single-producer transfer cell. The cell
// stores a `Waker` value produced by calls to `register` and many threads can
// race to take the waker by calling `wake`.
//
// If a new `Waker` instance is produced by calling `register` before an existing
// one is consumed, then the existing one is overwritten.
//
// While `AtomicWaker` is single-producer, the implementation ensures memory
// safety. In the event of concurrent calls to `register`, there will be a
// single winner whose waker will get stored in the cell. The losers will not
// have their tasks woken. As such, callers should ensure to add synchronization
// to calls to `register`.
//
// The implementation uses a single `AtomicUsize` value to coordinate access to
// the `Waker` cell. There are two bits that are operated on independently. These
// are represented by `REGISTERING` and `WAKING`.
//
// The `REGISTERING` bit is set when a producer enters the critical section. The
// `WAKING` bit is set when a consumer enters the critical section. Neither
// bit being set is represented by `WAITING`.
//
// A thread obtains an exclusive lock on the waker cell by transitioning the
// state from `WAITING` to `REGISTERING` or `WAKING`, depending on the
// operation the thread wishes to perform. When this transition is made, it is
// guaranteed that no other thread will access the waker cell.
//
// # Registering
//
// On a call to `register`, an attempt to transition the state from WAITING to
// REGISTERING is made. On success, the caller obtains a lock on the waker cell.
//
// If the lock is obtained, then the thread sets the waker cell to the waker
// provided as an argument. Then it attempts to transition the state back from
// `REGISTERING` -> `WAITING`.
//
// If this transition is successful, then the registering process is complete
// and the next call to `wake` will observe the waker.
//
// If the transition fails, then there was a concurrent call to `wake` that
// was unable to access the waker cell (due to the registering thread holding the
// lock). To handle this, the registering thread removes the waker it just set
// from the cell and calls `wake` on it. This call to wake represents the
// attempt to wake by the other thread (that set the `WAKING` bit). The
// state is then transitioned from `REGISTERING | WAKING` back to `WAITING`.
// This transition must succeed because, at this point, the state cannot be
// transitioned by another thread.
//
// # Waking
//
// On a call to `wake`, an attempt to transition the state from `WAITING` to
// `WAKING` is made. On success, the caller obtains a lock on the waker cell.
//
// If the lock is obtained, then the thread takes ownership of the current value
// in the waker cell, and calls `wake` on it. The state is then transitioned
// back to `WAITING`. This transition must succeed as, at this point, the state
// cannot be transitioned by another thread.
//
// If the thread is unable to obtain the lock, the `WAKING` bit is still.
// This is because it has either been set by the current thread but the previous
// value included the `REGISTERING` bit **or** a concurrent thread is in the
// `WAKING` critical section. Either way, no action must be taken.
//
// If the current thread is the only concurrent call to `wake` and another
// thread is in the `register` critical section, when the other thread **exits**
// the `register` critical section, it will observe the `WAKING` bit and
// handle the waker itself.
//
// If another thread is in the `waker` critical section, then it will handle
// waking the caller task.
//
// # A potential race (is safely handled).
//
// Imagine the following situation:
//
// * Thread A obtains the `wake` lock and wakes a task.
//
// * Before thread A releases the `wake` lock, the woken task is scheduled.
//
// * Thread B attempts to wake the task. In theory this should result in the
//   task being woken, but it cannot because thread A still holds the wake
//   lock.
//
// This case is handled by requiring users of `AtomicWaker` to call `register`
// **before** attempting to observe the application state change that resulted
// in the task being woken. The wakers also change the application state
// before calling wake.
//
// Because of this, the task will do one of two things.
//
// 1) Observe the application state change that Thread B is waking on. In
//    this case, it is OK for Thread B's wake to be lost.
//
// 2) Call register before attempting to observe the application state. Since
//    Thread A still holds the `wake` lock, the call to `register` will result
//    in the task waking itself and get scheduled again.

/// Idle state
const WAITING: usize = 0;

/// A new waker value is being registered with the `AtomicWaker` cell.
const REGISTERING: usize = 0b01;

/// The task currently registered with the `AtomicWaker` cell is being woken.
const WAKING: usize = 0b10;

impl AtomicWaker {
    /// Create an `AtomicWaker`
    pub(crate) fn new() -> AtomicWaker {
        AtomicWaker {
            state: AtomicUsize::new(WAITING),
            waker: UnsafeCell::new(None),
        }
    }

    /*
    /// Registers the current waker to be notified on calls to `wake`.
    pub(crate) fn register(&self, waker: Waker) {
        self.do_register(waker);
    }
    */

    /// Registers the provided waker to be notified on calls to `wake`.
    ///
    /// The new waker will take place of any previous wakers that were registered
    /// by previous calls to `register`. Any calls to `wake` that happen after
    /// a call to `register` (as defined by the memory ordering rules), will
    /// wake the `register` caller's task.
    ///
    /// It is safe to call `register` with multiple other threads concurrently
    /// calling `wake`. This will result in the `register` caller's current
    /// task being woken once.
    ///
    /// This function is safe to call concurrently, but this is generally a bad
    /// idea. Concurrent calls to `register` will attempt to register different
    /// tasks to be woken. One of the callers will win and have its task set,
    /// but there is no guarantee as to which caller will succeed.
    pub(crate) fn register_by_ref(&self, waker: &Waker) {
        self.do_register(waker);
    }

    fn do_register<W>(&self, waker: W)
    where
        W: WakerRef,
    {
        match self
            .state
            .compare_exchange(WAITING, REGISTERING, Acquire, Acquire)
            .unwrap_or_else(|x| x)
        {
            WAITING => {
                unsafe {
                    // Locked acquired, update the waker cell
                    self.waker.with_mut(|t| *t = Some(waker.into_waker()));

                    // Release the lock. If the state transitioned to include
                    // the `WAKING` bit, this means that a wake has been
                    // called concurrently, so we have to remove the waker and
                    // wake it.`
                    //
                    // Start by assuming that the state is `REGISTERING` as this
                    // is what we jut set it to.
                    let res = self
                        .state
                        .compare_exchange(REGISTERING, WAITING, AcqRel, Acquire);

                    match res {
                        Ok(_) => {}
                        Err(actual) => {
                            // This branch can only be reached if a
                            // concurrent thread called `wake`. In this
                            // case, `actual` **must** be `REGISTERING |
                            // `WAKING`.
                            debug_assert_eq!(actual, REGISTERING | WAKING);

                            // Take the waker to wake once the atomic operation has
                            // completed.
                            let waker = self.waker.with_mut(|t| (*t).take()).unwrap();

                            // Just swap, because no one could change state
                            // while state == `Registering | `Waking`
                            self.state.swap(WAITING, AcqRel);

                            // The atomic swap was complete, now
                            // wake the waker and return.
                            waker.wake();
                        }
                    }
                }
            }
            WAKING => {
                // Currently in the process of waking the task, i.e.,
                // `wake` is currently being called on the old waker.
                // So, we call wake on the new waker.
                waker.wake();

                // This is equivalent to a spin lock, so use a spin hint.
                // TODO: once we bump MSRV to 1.49+, use `hint::spin_loop` instead.
                #[allow(deprecated)]
                atomic::spin_loop_hint();
            }
            state => {
                // In this case, a concurrent thread is holding the
                // "registering" lock. This probably indicates a bug in the
                // caller's code as racing to call `register` doesn't make much
                // sense.
                //
                // We just want to maintain memory safety. It is ok to drop the
                // call to `register`.
                debug_assert!(state == REGISTERING || state == REGISTERING | WAKING);
            }
        }
    }

    /// Wakes the task that last called `register`.
    ///
    /// If `register` has not been called yet, then this does nothing.
    pub(crate) fn wake(&self) {
        if let Some(waker) = self.take_waker() {
            waker.wake();
        }
    }

    /// Attempts to take the `Waker` value out of the `AtomicWaker` with the
    /// intention that the caller will wake the task later.
    pub(crate) fn take_waker(&self) -> Option<Waker> {
        // AcqRel ordering is used in order to acquire the value of the `waker`
        // cell as well as to establish a `release` ordering with whatever
        // memory the `AtomicWaker` is associated with.
        match self.state.fetch_or(WAKING, AcqRel) {
            WAITING => {
                // The waking lock has been acquired.
                let waker = unsafe { self.waker.with_mut(|t| (*t).take()) };

                // Release the lock
                self.state.fetch_and(!WAKING, Release);

                waker
            }
            state => {
                // There is a concurrent thread currently updating the
                // associated waker.
                //
                // Nothing more to do as the `WAKING` bit has been set. It
                // doesn't matter if there are concurrent registering threads or
                // not.
                //
                debug_assert!(
                    state == REGISTERING || state == REGISTERING | WAKING || state == WAKING
                );
                None
            }
        }
    }
}

impl Default for AtomicWaker {
    fn default() -> Self {
        AtomicWaker::new()
    }
}

impl fmt::Debug for AtomicWaker {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(fmt, "AtomicWaker")
    }
}

unsafe impl Send for AtomicWaker {}
unsafe impl Sync for AtomicWaker {}

trait WakerRef {
    fn wake(self);
    fn into_waker(self) -> Waker;
}

impl WakerRef for Waker {
    fn wake(self) {
        self.wake()
    }

    fn into_waker(self) -> Waker {
        self
    }
}

impl WakerRef for &Waker {
    fn wake(self) {
        self.wake_by_ref()
    }

    fn into_waker(self) -> Waker {
        self.clone()
    }
}
<|endoftext|>


<commit_before>use kay::{World, TypedID};
use descartes::{P2, V2, Band, Segment, Path};
use monet::{RendererID, Renderable, RenderableID, Instance};
use stagemaster::geometry::{band_to_geometry, CPath};
use style::colors;

use super::{PlanManager, PlanManagerID};
use super::interaction::{ControlPointRef, CONTROL_POINT_HANDLE_RADIUS};

impl Renderable for PlanManager {
    fn setup_in_scene(&mut self, renderer_id: RendererID, scene_id: usize, world: &mut World) {
        let dot_geometry = band_to_geometry(
            &Band::new(
                CPath::new(
                    Segment::arc_with_direction(
                        P2::new(-CONTROL_POINT_HANDLE_RADIUS, 0.0),
                        V2::new(0.0, 1.0),
                        P2::new(CONTROL_POINT_HANDLE_RADIUS, 0.0),
                    ).into_iter()
                        .chain(Segment::arc_with_direction(
                            P2::new(CONTROL_POINT_HANDLE_RADIUS, 0.0),
                            V2::new(0.0, -1.0),
                            P2::new(-CONTROL_POINT_HANDLE_RADIUS, 0.0),
                        ))
                        .collect(),
                ),
                0.3,
            ),
            1.0,
        );

        renderer_id.add_batch(scene_id, 20_000, dot_geometry, world);
    }

    fn render_to_scene(
        &mut self,
        renderer_id: RendererID,
        scene_id: usize,
        frame: usize,
        world: &mut World,
    ) {
        // TODO: clean up this mess
        let proposal_id = self.ui_state
            .get(renderer_id.as_raw().machine)
            .expect("should have ui state for this renderer")
            .current_proposal;
        let (preview, result_preview) =
            self.ensure_preview(renderer_id.as_raw().machine, proposal_id);

        for (i, gesture) in preview.gestures.values().enumerate() {
            if gesture.points.len() >= 2 {
                let line_path = CPath::new(
                    gesture
                        .points
                        .windows(2)
                        .filter_map(|window| Segment::line(window[0], window[1]))
                        .collect(),
                );

                let line_geometry = band_to_geometry(&Band::new(line_path, 0.3), 1.0);

                renderer_id.update_individual(
                    scene_id,
                    19_000 + i as u16,
                    line_geometry,
                    Instance::with_color(colors::GESTURE_LINES),
                    true,
                    world,
                );
            }
        }

        let selected_points = &self.ui_state
            .get(renderer_id.as_raw().machine)
            .expect("should have ui state for this renderer")
            .selected_points;

        let control_point_instances = preview
            .gestures
            .pairs()
            .flat_map(|(gesture_id, gesture)| {
                gesture.points.iter().enumerate().map(move |(point_index,
                       point)| {
                    Instance {
                        instance_position: [point.x, point.y, 0.0],
                        instance_direction: [1.0, 0.0],
                        instance_color: if selected_points.contains(&ControlPointRef(
                            *gesture_id,
                            point_index,
                        ))
                        {
                            colors::CONTROL_POINT_SELECTED
                        } else {
                            colors::CONTROL_POINT
                        },
                    }
                })
            })
            .collect();

        renderer_id.add_several_instances(scene_id, 20_000, frame, control_point_instances, world);
    }
}

pub mod kay_auto;
use self::kay_auto::*;
pub use self::kay_auto::auto_setup;<commit_msg>Forgot rendering<commit_after>use kay::{World, TypedID};
use descartes::{P2, V2, Band, Segment, Path};
use monet::{RendererID, Renderable, RenderableID, Instance};
use stagemaster::geometry::{band_to_geometry, CPath};
use style::colors;

use super::{PlanManager, PlanManagerID};
use super::interaction::{ControlPointRef, CONTROL_POINT_HANDLE_RADIUS};

impl Renderable for PlanManager {
    fn setup_in_scene(&mut self, renderer_id: RendererID, scene_id: usize, world: &mut World) {
        let dot_geometry = band_to_geometry(
            &Band::new(
                CPath::new(
                    Segment::arc_with_direction(
                        P2::new(-CONTROL_POINT_HANDLE_RADIUS, 0.0),
                        V2::new(0.0, 1.0),
                        P2::new(CONTROL_POINT_HANDLE_RADIUS, 0.0),
                    ).into_iter()
                        .chain(Segment::arc_with_direction(
                            P2::new(CONTROL_POINT_HANDLE_RADIUS, 0.0),
                            V2::new(0.0, -1.0),
                            P2::new(-CONTROL_POINT_HANDLE_RADIUS, 0.0),
                        ))
                        .collect(),
                ),
                0.3,
            ),
            1.0,
        );

        renderer_id.add_batch(scene_id, 20_000, dot_geometry, world);
    }

    fn render_to_scene(
        &mut self,
        renderer_id: RendererID,
        scene_id: usize,
        frame: usize,
        world: &mut World,
    ) {
        // TODO: clean up this mess
        let proposal_id = self.ui_state
            .get(renderer_id.as_raw().machine)
            .expect("should have ui state for this renderer")
            .current_proposal;
        let (preview, result_preview) =
            self.ensure_preview(renderer_id.as_raw().machine, proposal_id);

        super::transport_planning_new::render_preview(
            result_preview,
            renderer_id,
            scene_id,
            frame,
            world,
        );

        for (i, gesture) in preview.gestures.values().enumerate() {
            if gesture.points.len() >= 2 {
                let line_path = CPath::new(
                    gesture
                        .points
                        .windows(2)
                        .filter_map(|window| Segment::line(window[0], window[1]))
                        .collect(),
                );

                let line_geometry = band_to_geometry(&Band::new(line_path, 0.3), 1.0);

                renderer_id.update_individual(
                    scene_id,
                    19_000 + i as u16,
                    line_geometry,
                    Instance::with_color(colors::GESTURE_LINES),
                    true,
                    world,
                );
            }
        }

        let selected_points = &self.ui_state
            .get(renderer_id.as_raw().machine)
            .expect("should have ui state for this renderer")
            .selected_points;

        let control_point_instances = preview
            .gestures
            .pairs()
            .flat_map(|(gesture_id, gesture)| {
                gesture.points.iter().enumerate().map(move |(point_index,
                       point)| {
                    Instance {
                        instance_position: [point.x, point.y, 0.0],
                        instance_direction: [1.0, 0.0],
                        instance_color: if selected_points.contains(&ControlPointRef(
                            *gesture_id,
                            point_index,
                        ))
                        {
                            colors::CONTROL_POINT_SELECTED
                        } else {
                            colors::CONTROL_POINT
                        },
                    }
                })
            })
            .collect();

        renderer_id.add_several_instances(scene_id, 20_000, frame, control_point_instances, world);
    }
}

pub mod kay_auto;
use self::kay_auto::*;
pub use self::kay_auto::auto_setup;<|endoftext|>


<commit_before>use crate::future::{FutureObj, LocalFutureObj};
use core::fmt;

/// The `Spawn` trait allows for pushing futures onto an executor that will
/// run them to completion.
pub trait Spawn {
    /// Spawns a future that will be run to completion.
    ///
    /// # Errors
    ///
    /// The executor may be unable to spawn tasks. Spawn errors should
    /// represent relatively rare scenarios, such as the executor
    /// having been shut down so that it is no longer able to accept
    /// tasks.
    fn spawn_obj(&mut self, future: FutureObj<'static, ()>)
        -> Result<(), SpawnError>;

    /// Determines whether the executor is able to spawn new tasks.
    ///
    /// This method will return `Ok` when the executor is *likely*
    /// (but not guaranteed) to accept a subsequent spawn attempt.
    /// Likewise, an `Err` return means that `spawn` is likely, but
    /// not guaranteed, to yield an error.
    #[inline]
    fn status(&self) -> Result<(), SpawnError> {
        Ok(())
    }
}

/// The `LocalSpawn` is similar to `[Spawn]`, but allows spawning futures
/// that don't implement `Send`.
pub trait LocalSpawn {
    /// Spawns a future that will be run to completion.
    ///
    /// # Errors
    ///
    /// The executor may be unable to spawn tasks. Spawn errors should
    /// represent relatively rare scenarios, such as the executor
    /// having been shut down so that it is no longer able to accept
    /// tasks.
    fn spawn_local_obj(&mut self, future: LocalFutureObj<'static, ()>)
        -> Result<(), SpawnError>;

    /// Determines whether the executor is able to spawn new tasks.
    ///
    /// This method will return `Ok` when the executor is *likely*
    /// (but not guaranteed) to accept a subsequent spawn attempt.
    /// Likewise, an `Err` return means that `spawn` is likely, but
    /// not guaranteed, to yield an error.
    #[inline]
    fn status_local(&self) -> Result<(), SpawnError> {
        Ok(())
    }
}

/// An error that occurred during spawning.
pub struct SpawnError {
    _hidden: (),
}

impl fmt::Debug for SpawnError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_tuple("SpanError")
            .field(&"shutdown")
            .finish()
    }
}

impl SpawnError {
    /// Spawning failed because the executor has been shut down.
    pub fn shutdown() -> Self {
        Self { _hidden: () }
    }

    /// Check whether spawning failed to the executor being shut down.
    pub fn is_shutdown(&self) -> bool {
        true
    }
}

#[cfg(feature = "alloc")]
mod if_alloc {
    use alloc::boxed::Box;
    use super::*;

    impl<Sp: ?Sized + Spawn> Spawn for Box<Sp> {
        fn spawn_obj(&mut self, future: FutureObj<'static, ()>)
        -> Result<(), SpawnError> {
            (**self).spawn_obj(future)
        }

        fn status(&self) -> Result<(), SpawnError> {
            (**self).status()
        }
    }

    impl<Sp: ?Sized + LocalSpawn> LocalSpawn for Box<Sp> {
        fn spawn_local_obj(&mut self, future: LocalFutureObj<'static, ()>)
        -> Result<(), SpawnError> {
            (**self).spawn_local_obj(future)
        }

        fn status_local(&self) -> Result<(), SpawnError> {
            (**self).status_local()
        }
    }
}
<commit_msg>Fix spelling<commit_after>use crate::future::{FutureObj, LocalFutureObj};
use core::fmt;

/// The `Spawn` trait allows for pushing futures onto an executor that will
/// run them to completion.
pub trait Spawn {
    /// Spawns a future that will be run to completion.
    ///
    /// # Errors
    ///
    /// The executor may be unable to spawn tasks. Spawn errors should
    /// represent relatively rare scenarios, such as the executor
    /// having been shut down so that it is no longer able to accept
    /// tasks.
    fn spawn_obj(&mut self, future: FutureObj<'static, ()>)
        -> Result<(), SpawnError>;

    /// Determines whether the executor is able to spawn new tasks.
    ///
    /// This method will return `Ok` when the executor is *likely*
    /// (but not guaranteed) to accept a subsequent spawn attempt.
    /// Likewise, an `Err` return means that `spawn` is likely, but
    /// not guaranteed, to yield an error.
    #[inline]
    fn status(&self) -> Result<(), SpawnError> {
        Ok(())
    }
}

/// The `LocalSpawn` is similar to `[Spawn]`, but allows spawning futures
/// that don't implement `Send`.
pub trait LocalSpawn {
    /// Spawns a future that will be run to completion.
    ///
    /// # Errors
    ///
    /// The executor may be unable to spawn tasks. Spawn errors should
    /// represent relatively rare scenarios, such as the executor
    /// having been shut down so that it is no longer able to accept
    /// tasks.
    fn spawn_local_obj(&mut self, future: LocalFutureObj<'static, ()>)
        -> Result<(), SpawnError>;

    /// Determines whether the executor is able to spawn new tasks.
    ///
    /// This method will return `Ok` when the executor is *likely*
    /// (but not guaranteed) to accept a subsequent spawn attempt.
    /// Likewise, an `Err` return means that `spawn` is likely, but
    /// not guaranteed, to yield an error.
    #[inline]
    fn status_local(&self) -> Result<(), SpawnError> {
        Ok(())
    }
}

/// An error that occurred during spawning.
pub struct SpawnError {
    _hidden: (),
}

impl fmt::Debug for SpawnError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_tuple("SpawnError")
            .field(&"shutdown")
            .finish()
    }
}

impl SpawnError {
    /// Spawning failed because the executor has been shut down.
    pub fn shutdown() -> Self {
        Self { _hidden: () }
    }

    /// Check whether spawning failed to the executor being shut down.
    pub fn is_shutdown(&self) -> bool {
        true
    }
}

#[cfg(feature = "alloc")]
mod if_alloc {
    use alloc::boxed::Box;
    use super::*;

    impl<Sp: ?Sized + Spawn> Spawn for Box<Sp> {
        fn spawn_obj(&mut self, future: FutureObj<'static, ()>)
        -> Result<(), SpawnError> {
            (**self).spawn_obj(future)
        }

        fn status(&self) -> Result<(), SpawnError> {
            (**self).status()
        }
    }

    impl<Sp: ?Sized + LocalSpawn> LocalSpawn for Box<Sp> {
        fn spawn_local_obj(&mut self, future: LocalFutureObj<'static, ()>)
        -> Result<(), SpawnError> {
            (**self).spawn_local_obj(future)
        }

        fn status_local(&self) -> Result<(), SpawnError> {
            (**self).status_local()
        }
    }
}
<|endoftext|>


<commit_before>use futures::executor::block_on;
use futures::io::AsyncReadExt;

#[test]
fn read_exact() {
    let mut reader: &[u8] = &[1, 2, 3, 4, 5];
    let mut out = [0u8; 3];

    let res = block_on(reader.read_exact(&mut out)); // read 3 bytes out
    assert!(res.is_ok());
    assert_eq!(out, [1,2,3]);
    assert_eq!(reader.len(), 2);

    let res = block_on(reader.read_exact(&mut out)); // read another 3 bytes, but only 2 bytes left
    assert!(res.is_err());
    assert_eq!(reader.len(), 0);
}
<commit_msg>futures: tests/io_read_exact.rs: Don't fail w/o executor<commit_after>#[cfg(feature = "executor")]
#[test]
fn read_exact() {
    use futures::executor::block_on;
    use futures::io::AsyncReadExt;

    let mut reader: &[u8] = &[1, 2, 3, 4, 5];
    let mut out = [0u8; 3];

    let res = block_on(reader.read_exact(&mut out)); // read 3 bytes out
    assert!(res.is_ok());
    assert_eq!(out, [1,2,3]);
    assert_eq!(reader.len(), 2);

    let res = block_on(reader.read_exact(&mut out)); // read another 3 bytes, but only 2 bytes left
    assert!(res.is_err());
    assert_eq!(reader.len(), 0);
}
<|endoftext|>