<commit_before>use std::ptr;

use libudev_c;
use util;
use iterator;
use device;

use udev::Udev;
use device::Device;
use iterator::{UdevIterator, PathIterator};

pub struct Enumerator<'u> {
    pub udev: &'u Udev,
    enumerator: libudev_c::udev_enumerate
}

// Crate Private
pub unsafe fn enumerator<'u>(udev: &'u Udev, enumerator: libudev_c::udev_enumerate) -> Enumerator<'u> {
    Enumerator {
        udev: udev,
        enumerator: enumerator
    }
}

impl<'u> Enumerator<'u> {
    /// Include devices with the specified subsystem.
    ///
    /// All devices added by future scans will match either the specified subsystem or a subsystem
    /// specified in a previous invocation of this function (on this enumerator). If this function
    /// has never been called, devices will not be filtered by subsystem.
    pub fn match_subsystem(self, subsystem: &str) -> Enumerator<'u> {
        subsystem.with_c_str(|subsystem| util::handle_error(unsafe {
            libudev_c::udev_enumerate_add_match_subsystem(self.enumerator, subsystem)
        }));
        self
    }

    /// Exclude devices with the specified subsystem.
    ///
    /// No device added by a future scan will have the specified subsystem.
    pub fn match_not_subsystem(self, subsystem: &str) -> Enumerator<'u> {
        subsystem.with_c_str(|subsystem| util::handle_error(unsafe {
            libudev_c::udev_enumerate_add_nomatch_subsystem(self.enumerator, subsystem)
        }));
        self
    }

    /// Only include devices with an attribute.
    ///
    /// All devices added by future scans will have the specified attribute with
    /// the (optionally) specified value.
    pub fn match_attribute(self, attr: &str, value: Option<&str>) -> Enumerator<'u> {
        fn it(e: &Enumerator, attr: *const i8, value: *const i8) {
            util::handle_error(unsafe {libudev_c::udev_enumerate_add_match_sysattr(e.enumerator, attr, value)});
        }
        attr.with_c_str(|attr| match value {
            Some(value) => value.with_c_str(|value| it(&self, attr, value)),
            None => it(&self, attr, ptr::null())
        });
        self
    }

    /// Exclude devices with an attribute.
    ///
    /// No device added by future scans will have the specified attribute with
    /// the (optionally) specified value.
    pub fn match_not_attribute(self, attr: &str, value: Option<&str>) -> Enumerator<'u> {
        fn it(e: &Enumerator, attr: *const i8, value: *const i8) {
            util::handle_error(unsafe {libudev_c::udev_enumerate_add_nomatch_sysattr(e.enumerator, attr, value)});
        }
        attr.with_c_str(|attr| match value {
            Some(value) => value.with_c_str(|value| it(&self, attr, value)),
            None => it(&self, attr, ptr::null())
        });
        self
    }

    /// Only include devices with a property.
    ///
    /// All devices added by future scans will have the specified property with
    /// the (optionally) specified value.
    pub fn match_property(self, attr: &str, value: Option<&str>) -> Enumerator<'u> {
        fn it(e: &Enumerator, attr: *const i8, value: *const i8) {
            util::handle_error(unsafe {libudev_c::udev_enumerate_add_match_property(e.enumerator, attr, value)});
        }
        attr.with_c_str(|attr| match value {
            Some(value) => value.with_c_str(|value| it(&self, attr, value)),
            None => it(&self, attr, ptr::null())
        });
        self
    }

    /// Only include children of the specified device.
    ///
    /// All devices added by future scans (until the parent is changed/cleared)
    /// will have the specified parent.
    pub fn match_parent(self, parent: &Device) -> Enumerator<'u> {
        unsafe {
            util::handle_error(libudev_c::udev_enumerate_add_match_parent(self.enumerator, device::device_get_dev(parent)));
        }
        self
    }

    /// Remove the parent restriction.
    ///
    /// Clear the current parent match. Future scans will add devices regardless of their parents.
    pub fn clear_parent(self) -> Enumerator<'u> {
        unsafe {
            util::handle_error(libudev_c::udev_enumerate_add_match_parent(self.enumerator, ptr::null_mut()));
        }
        self
    }

    /// Only include devices with the specified tag.
    ///
    /// All devices added by future scans will match the specified tag.
    pub fn match_tag(self, tag: &str) -> Enumerator<'u> {
        tag.with_c_str(|tag| util::handle_error( unsafe {
            libudev_c::udev_enumerate_add_match_tag(self.enumerator, tag)
        }));
        self
    }

    /// Include only initialized devices.
    ///
    /// All devices added by future scans will be initialized.
    pub fn match_is_initialized(self) -> Enumerator<'u> {
        util::handle_error(unsafe {
            libudev_c::udev_enumerate_add_match_is_initialized(self.enumerator)
        });
        self
    }

    /// Include devices with the specified sysname.
    ///
    /// All devices added by future scans will match either the specified sysname or a sysname
    /// specified in a previous invocation of this function (on this enumerator). If this function
    /// has never been called, devices will not be filtered by sysname.
    pub fn match_sysname(self, sysname: &str) -> Enumerator<'u> {
        sysname.with_c_str(|sysname| util::handle_error( unsafe {
            libudev_c::udev_enumerate_add_match_sysname(self.enumerator, sysname)
        }));
        self
    }

    /// Manually include a device.
    ///
    /// Manually add a device to the enumerator bypassing matches. According to the libudev
    /// documentation, this can be useful for determine device dependency order (see iter below).
    pub fn add_device(self, device: &Device) -> Enumerator<'u> {
        device.syspath().with_c_str(|syspath| util::handle_error(unsafe{
            libudev_c::udev_enumerate_add_syspath(self.enumerator, syspath)
        }));
        self
    }

    /// Scan subsystems
    ///
    /// Scan sysfs for subsystems matching all previously applied constraints and add them to the
    /// enumerator.
    pub fn scan_subsystems(self) -> Enumerator<'u> {
        util::handle_error(unsafe { libudev_c::udev_enumerate_scan_subsystems(self.enumerator) });
        self
    }

    /// Scan devices
    ///
    /// Scan sysfs for devices matching all previously applied constraints and add them to the
    /// enumerator.
    pub fn scan_devices(self) -> Enumerator<'u> {
        util::handle_error(unsafe { libudev_c::udev_enumerate_scan_devices(self.enumerator) });
        self
    }

    /// Iterate over all devices that have been added to this iterator in dependency order.
    ///
    /// # Note
    ///
    /// Enumerators are not prepopulated with devices. If you haven't either manually added devices
    /// to the enumerator (`add_device`), or haven't called a scan method (`scan_subsystems` or
    /// `scan_devices`), this iterator will be empty.
    pub fn iter(&self) -> DeviceIterator {
        DeviceIterator {
            iter : UdevIterator {
                       parent: self,
                       entry: unsafe { libudev_c::udev_enumerate_get_list_entry(self.enumerator) }
                   }
        }
    }

    /// Same as `iter` but avoid creating device objects.
    pub fn iter_paths(&self) -> PathIterator {
        unsafe {
            iterator::path_iterator(self, libudev_c::udev_enumerate_get_list_entry(self.enumerator))
        }
    }

}

pub struct DeviceIterator<'e, 'u: 'e> {
    iter: UdevIterator<'e, Enumerator<'u>>
}

impl<'e, 'u> Iterator<Device<'u>> for DeviceIterator<'e, 'u> {
    fn next(&mut self) -> Option<Device<'u>> {
        self.iter.next().and_then(|(key, _)| self.iter.parent.udev.device(&Path::new(key)))
    }
}

#[unsafe_destructor]
impl<'p> Drop for Enumerator<'p> {
    fn drop(&mut self) {
        unsafe {
            libudev_c::udev_enumerate_unref(self.enumerator);
        }
    }
}
<commit_msg>Fix Enumerator::match_parent documentation.<commit_after>use std::ptr;

use libudev_c;
use util;
use iterator;
use device;

use udev::Udev;
use device::Device;
use iterator::{UdevIterator, PathIterator};

pub struct Enumerator<'u> {
    pub udev: &'u Udev,
    enumerator: libudev_c::udev_enumerate
}

// Crate Private
pub unsafe fn enumerator<'u>(udev: &'u Udev, enumerator: libudev_c::udev_enumerate) -> Enumerator<'u> {
    Enumerator {
        udev: udev,
        enumerator: enumerator
    }
}

impl<'u> Enumerator<'u> {
    /// Include devices with the specified subsystem.
    ///
    /// All devices added by future scans will match either the specified subsystem or a subsystem
    /// specified in a previous invocation of this function (on this enumerator). If this function
    /// has never been called, devices will not be filtered by subsystem.
    pub fn match_subsystem(self, subsystem: &str) -> Enumerator<'u> {
        subsystem.with_c_str(|subsystem| util::handle_error(unsafe {
            libudev_c::udev_enumerate_add_match_subsystem(self.enumerator, subsystem)
        }));
        self
    }

    /// Exclude devices with the specified subsystem.
    ///
    /// No device added by a future scan will have the specified subsystem.
    pub fn match_not_subsystem(self, subsystem: &str) -> Enumerator<'u> {
        subsystem.with_c_str(|subsystem| util::handle_error(unsafe {
            libudev_c::udev_enumerate_add_nomatch_subsystem(self.enumerator, subsystem)
        }));
        self
    }

    /// Only include devices with an attribute.
    ///
    /// All devices added by future scans will have the specified attribute with
    /// the (optionally) specified value.
    pub fn match_attribute(self, attr: &str, value: Option<&str>) -> Enumerator<'u> {
        fn it(e: &Enumerator, attr: *const i8, value: *const i8) {
            util::handle_error(unsafe {libudev_c::udev_enumerate_add_match_sysattr(e.enumerator, attr, value)});
        }
        attr.with_c_str(|attr| match value {
            Some(value) => value.with_c_str(|value| it(&self, attr, value)),
            None => it(&self, attr, ptr::null())
        });
        self
    }

    /// Exclude devices with an attribute.
    ///
    /// No device added by future scans will have the specified attribute with
    /// the (optionally) specified value.
    pub fn match_not_attribute(self, attr: &str, value: Option<&str>) -> Enumerator<'u> {
        fn it(e: &Enumerator, attr: *const i8, value: *const i8) {
            util::handle_error(unsafe {libudev_c::udev_enumerate_add_nomatch_sysattr(e.enumerator, attr, value)});
        }
        attr.with_c_str(|attr| match value {
            Some(value) => value.with_c_str(|value| it(&self, attr, value)),
            None => it(&self, attr, ptr::null())
        });
        self
    }

    /// Only include devices with a property.
    ///
    /// All devices added by future scans will have the specified property with
    /// the (optionally) specified value.
    pub fn match_property(self, attr: &str, value: Option<&str>) -> Enumerator<'u> {
        fn it(e: &Enumerator, attr: *const i8, value: *const i8) {
            util::handle_error(unsafe {libudev_c::udev_enumerate_add_match_property(e.enumerator, attr, value)});
        }
        attr.with_c_str(|attr| match value {
            Some(value) => value.with_c_str(|value| it(&self, attr, value)),
            None => it(&self, attr, ptr::null())
        });
        self
    }

    /// Only include the specified device and its children.
    ///
    /// All devices added by future scans (until the parent is changed/cleared)
    /// will have/be the specified parent.
    pub fn match_parent(self, parent: &Device) -> Enumerator<'u> {
        unsafe {
            util::handle_error(libudev_c::udev_enumerate_add_match_parent(self.enumerator, device::device_get_dev(parent)));
        }
        self
    }

    /// Remove the parent restriction.
    ///
    /// Clear the current parent match. Future scans will add devices regardless of their parents.
    pub fn clear_parent(self) -> Enumerator<'u> {
        unsafe {
            util::handle_error(libudev_c::udev_enumerate_add_match_parent(self.enumerator, ptr::null_mut()));
        }
        self
    }

    /// Only include devices with the specified tag.
    ///
    /// All devices added by future scans will match the specified tag.
    pub fn match_tag(self, tag: &str) -> Enumerator<'u> {
        tag.with_c_str(|tag| util::handle_error( unsafe {
            libudev_c::udev_enumerate_add_match_tag(self.enumerator, tag)
        }));
        self
    }

    /// Include only initialized devices.
    ///
    /// All devices added by future scans will be initialized.
    pub fn match_is_initialized(self) -> Enumerator<'u> {
        util::handle_error(unsafe {
            libudev_c::udev_enumerate_add_match_is_initialized(self.enumerator)
        });
        self
    }

    /// Include devices with the specified sysname.
    ///
    /// All devices added by future scans will match either the specified sysname or a sysname
    /// specified in a previous invocation of this function (on this enumerator). If this function
    /// has never been called, devices will not be filtered by sysname.
    pub fn match_sysname(self, sysname: &str) -> Enumerator<'u> {
        sysname.with_c_str(|sysname| util::handle_error( unsafe {
            libudev_c::udev_enumerate_add_match_sysname(self.enumerator, sysname)
        }));
        self
    }

    /// Manually include a device.
    ///
    /// Manually add a device to the enumerator bypassing matches. According to the libudev
    /// documentation, this can be useful for determine device dependency order (see iter below).
    pub fn add_device(self, device: &Device) -> Enumerator<'u> {
        device.syspath().with_c_str(|syspath| util::handle_error(unsafe{
            libudev_c::udev_enumerate_add_syspath(self.enumerator, syspath)
        }));
        self
    }

    /// Scan subsystems
    ///
    /// Scan sysfs for subsystems matching all previously applied constraints and add them to the
    /// enumerator.
    pub fn scan_subsystems(self) -> Enumerator<'u> {
        util::handle_error(unsafe { libudev_c::udev_enumerate_scan_subsystems(self.enumerator) });
        self
    }

    /// Scan devices
    ///
    /// Scan sysfs for devices matching all previously applied constraints and add them to the
    /// enumerator.
    pub fn scan_devices(self) -> Enumerator<'u> {
        util::handle_error(unsafe { libudev_c::udev_enumerate_scan_devices(self.enumerator) });
        self
    }

    /// Iterate over all devices that have been added to this iterator in dependency order.
    ///
    /// # Note
    ///
    /// Enumerators are not prepopulated with devices. If you haven't either manually added devices
    /// to the enumerator (`add_device`), or haven't called a scan method (`scan_subsystems` or
    /// `scan_devices`), this iterator will be empty.
    pub fn iter(&self) -> DeviceIterator {
        DeviceIterator {
            iter : UdevIterator {
                       parent: self,
                       entry: unsafe { libudev_c::udev_enumerate_get_list_entry(self.enumerator) }
                   }
        }
    }

    /// Same as `iter` but avoid creating device objects.
    pub fn iter_paths(&self) -> PathIterator {
        unsafe {
            iterator::path_iterator(self, libudev_c::udev_enumerate_get_list_entry(self.enumerator))
        }
    }

}

pub struct DeviceIterator<'e, 'u: 'e> {
    iter: UdevIterator<'e, Enumerator<'u>>
}

impl<'e, 'u> Iterator<Device<'u>> for DeviceIterator<'e, 'u> {
    fn next(&mut self) -> Option<Device<'u>> {
        self.iter.next().and_then(|(key, _)| self.iter.parent.udev.device(&Path::new(key)))
    }
}

#[unsafe_destructor]
impl<'p> Drop for Enumerator<'p> {
    fn drop(&mut self) {
        unsafe {
            libudev_c::udev_enumerate_unref(self.enumerator);
        }
    }
}
<|endoftext|>


<commit_before>use byteorder::{LittleEndian, WriteBytesExt};
use std::io::{self, Write};

use crate::color::ColorType;
use crate::error::ImageResult;
use crate::image::ImageEncoder;

use crate::codecs::png::PngEncoder;

// Enum value indicating an ICO image (as opposed to a CUR image):
const ICO_IMAGE_TYPE: u16 = 1;
// The length of an ICO file ICONDIR structure, in bytes:
const ICO_ICONDIR_SIZE: u32 = 6;
// The length of an ICO file DIRENTRY structure, in bytes:
const ICO_DIRENTRY_SIZE: u32 = 16;

/// ICO encoder
pub struct IcoEncoder<W: Write> {
    w: W,
}

impl<W: Write> IcoEncoder<W> {
    /// Create a new encoder that writes its output to ```w```.
    pub fn new(w: W) -> IcoEncoder<W> {
        IcoEncoder { w }
    }

    /// Encodes the image ```image``` that has dimensions ```width``` and
    /// ```height``` and ```ColorType``` ```c```.  The dimensions of the image
    /// must be between 1 and 256 (inclusive) or an error will be returned.
    ///
    /// Expects data to be big endian.
    #[deprecated = "Use `IcoEncoder::write_image` instead. Beware that `write_image` has a different endianness convention"]
    pub fn encode(
        mut self,
        data: &[u8],
        width: u32,
        height: u32,
        color: ColorType,
    ) -> ImageResult<()> {
        let mut image_data: Vec<u8> = Vec::new();
        #[allow(deprecated)]
        PngEncoder::new(&mut image_data).encode(data, width, height, color)?;

        write_icondir(&mut self.w, 1)?;
        write_direntry(
            &mut self.w,
            width,
            height,
            color,
            ICO_ICONDIR_SIZE + ICO_DIRENTRY_SIZE,
            image_data.len() as u32,
        )?;
        self.w.write_all(&image_data)?;
        Ok(())
    }

    /// Takes an already encoded PNG or BMP image and encodes it into an ICO.
    ///
    /// `width`, `height` and `color_type` should match the
    /// real properties of the `encoded_image`.
    ///
    /// The dimensions of the image must be between 1 and 256 (inclusive) or
    /// an error will be returned.
    pub fn write_pre_encoded_image(
        mut self,
        encoded_image: &[u8],
        width: u32,
        height: u32,
        color_type: ColorType,
    ) -> ImageResult<()> {
        write_icondir(&mut self.w, 1)?;
        write_direntry(
            &mut self.w,
            width,
            height,
            color_type,
            ICO_ICONDIR_SIZE + ICO_DIRENTRY_SIZE,
            encoded_image.len() as u32,
        )?;
        self.w.write_all(&encoded_image)?;
        Ok(())
    }
}

impl<W: Write> ImageEncoder for IcoEncoder<W> {
    /// Write an ICO image with the specified width, height, and color type.
    ///
    /// For color types with 16-bit per channel or larger, the contents of `buf` should be in
    /// native endian.
    ///
    /// WARNING: In image 0.23.14 and earlier this method erroneously expected buf to be in big endian.
    fn write_image(
        self,
        buf: &[u8],
        width: u32,
        height: u32,
        color_type: ColorType,
    ) -> ImageResult<()> {
        let mut image_data: Vec<u8> = Vec::new();
        PngEncoder::new(&mut image_data).write_image(buf, width, height, color_type)?;

        self.write_pre_encoded_image(&image_data, width, height, color_type)
    }
}

fn write_icondir<W: Write>(w: &mut W, num_images: u16) -> io::Result<()> {
    // Reserved field (must be zero):
    w.write_u16::<LittleEndian>(0)?;
    // Image type (ICO or CUR):
    w.write_u16::<LittleEndian>(ICO_IMAGE_TYPE)?;
    // Number of images in the file:
    w.write_u16::<LittleEndian>(num_images)?;
    Ok(())
}

fn write_direntry<W: Write>(
    w: &mut W,
    width: u32,
    height: u32,
    color: ColorType,
    data_start: u32,
    data_size: u32,
) -> io::Result<()> {
    // Image dimensions:
    write_width_or_height(w, width)?;
    write_width_or_height(w, height)?;
    // Number of colors in palette (or zero for no palette):
    w.write_u8(0)?;
    // Reserved field (must be zero):
    w.write_u8(0)?;
    // Color planes:
    w.write_u16::<LittleEndian>(0)?;
    // Bits per pixel:
    w.write_u16::<LittleEndian>(color.bits_per_pixel())?;
    // Image data size, in bytes:
    w.write_u32::<LittleEndian>(data_size)?;
    // Image data offset, in bytes:
    w.write_u32::<LittleEndian>(data_start)?;
    Ok(())
}

/// Encode a width/height value as a single byte, where 0 means 256.
fn write_width_or_height<W: Write>(w: &mut W, value: u32) -> io::Result<()> {
    if value < 1 || value > 256 {
        // TODO: this is not very idiomatic yet. Should return an EncodingError and be checked
        // prior to encoding.
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            "Invalid ICO dimensions (width and \
             height must be between 1 and 256)",
        ));
    }
    w.write_u8(if value < 256 { value as u8 } else { 0 })
}
<commit_msg>Make it possible to supply multiple images to the .ico encoder<commit_after>use byteorder::{LittleEndian, WriteBytesExt};
use std::io::{self, Write};

use crate::color::ColorType;
use crate::error::{ImageError, ImageResult, ParameterError, ParameterErrorKind};
use crate::image::ImageEncoder;

use crate::codecs::png::PngEncoder;

// Enum value indicating an ICO image (as opposed to a CUR image):
const ICO_IMAGE_TYPE: u16 = 1;
// The length of an ICO file ICONDIR structure, in bytes:
const ICO_ICONDIR_SIZE: u32 = 6;
// The length of an ICO file DIRENTRY structure, in bytes:
const ICO_DIRENTRY_SIZE: u32 = 16;

/// ICO encoder
pub struct IcoEncoder<W: Write> {
    w: W,
}

impl<W: Write> IcoEncoder<W> {
    /// Create a new encoder that writes its output to ```w```.
    pub fn new(w: W) -> IcoEncoder<W> {
        IcoEncoder { w }
    }

    /// Encodes the image ```image``` that has dimensions ```width``` and
    /// ```height``` and ```ColorType``` ```c```.  The dimensions of the image
    /// must be between 1 and 256 (inclusive) or an error will be returned.
    ///
    /// Expects data to be big endian.
    #[deprecated = "Use `IcoEncoder::write_image` instead. Beware that `write_image` has a different endianness convention"]
    pub fn encode(
        mut self,
        data: &[u8],
        width: u32,
        height: u32,
        color: ColorType,
    ) -> ImageResult<()> {
        let mut image_data: Vec<u8> = Vec::new();
        #[allow(deprecated)]
        PngEncoder::new(&mut image_data).encode(data, width, height, color)?;

        write_icondir(&mut self.w, 1)?;
        write_direntry(
            &mut self.w,
            width,
            height,
            color,
            ICO_ICONDIR_SIZE + ICO_DIRENTRY_SIZE,
            image_data.len() as u32,
        )?;
        self.w.write_all(&image_data)?;
        Ok(())
    }

    /// Takes some already encoded PNG or BMP images and encodes them into an ICO.
    ///
    /// `images` is a list of images, usually ordered by dimension.
    /// The items of the tuple composing the list are as follows:
    ///
    /// * `encoded_image`: a PNG or BMP image
    /// * `width`: the width of the `encoded_image`
    /// * `height`: the height of the `encoded_image`
    /// * `color_type`: the [`ColorType`] of the `encoded_image`
    ///
    /// The dimensions of the image must be between 1 and 256 (inclusive) or
    /// an error will be returned.
    /// `images` must have a lenght between 1 and 65535 (inclusive).
    pub fn write_pre_encoded_images(
        mut self,
        images: &[(&[u8], u32, u32, ColorType)],
    ) -> ImageResult<()> {
        if !(1..=usize::from(u16::MAX)).contains(&images.len()) {
            return Err(ImageError::Parameter(ParameterError::from_kind(
                ParameterErrorKind::Generic(format!(
                    "the number of images must be `1..=u16::MAX`, instead {} images were provided",
                    images.len(),
                )),
            )));
        }
        let num_images = images.len() as u16;

        let mut offset = ICO_ICONDIR_SIZE;
        write_icondir(&mut self.w, num_images)?;
        for &(encoded_image, width, height, color_type) in images {
            offset += ICO_DIRENTRY_SIZE;

            write_direntry(
                &mut self.w,
                width,
                height,
                color_type,
                offset,
                encoded_image.len() as u32,
            )?;

            offset += encoded_image.len() as u32;
        }
        for &(encoded_image, _width, _height, _color_type) in images {
            self.w.write_all(encoded_image)?;
        }
        Ok(())
    }
}

impl<W: Write> ImageEncoder for IcoEncoder<W> {
    /// Write an ICO image with the specified width, height, and color type.
    ///
    /// For color types with 16-bit per channel or larger, the contents of `buf` should be in
    /// native endian.
    ///
    /// WARNING: In image 0.23.14 and earlier this method erroneously expected buf to be in big endian.
    fn write_image(
        self,
        buf: &[u8],
        width: u32,
        height: u32,
        color_type: ColorType,
    ) -> ImageResult<()> {
        let mut image_data: Vec<u8> = Vec::new();
        PngEncoder::new(&mut image_data).write_image(buf, width, height, color_type)?;

        let images = [(image_data.as_slice(), width, height, color_type)];
        self.write_pre_encoded_images(&images)
    }
}

fn write_icondir<W: Write>(w: &mut W, num_images: u16) -> io::Result<()> {
    // Reserved field (must be zero):
    w.write_u16::<LittleEndian>(0)?;
    // Image type (ICO or CUR):
    w.write_u16::<LittleEndian>(ICO_IMAGE_TYPE)?;
    // Number of images in the file:
    w.write_u16::<LittleEndian>(num_images)?;
    Ok(())
}

fn write_direntry<W: Write>(
    w: &mut W,
    width: u32,
    height: u32,
    color: ColorType,
    data_start: u32,
    data_size: u32,
) -> io::Result<()> {
    // Image dimensions:
    write_width_or_height(w, width)?;
    write_width_or_height(w, height)?;
    // Number of colors in palette (or zero for no palette):
    w.write_u8(0)?;
    // Reserved field (must be zero):
    w.write_u8(0)?;
    // Color planes:
    w.write_u16::<LittleEndian>(0)?;
    // Bits per pixel:
    w.write_u16::<LittleEndian>(color.bits_per_pixel())?;
    // Image data size, in bytes:
    w.write_u32::<LittleEndian>(data_size)?;
    // Image data offset, in bytes:
    w.write_u32::<LittleEndian>(data_start)?;
    Ok(())
}

/// Encode a width/height value as a single byte, where 0 means 256.
fn write_width_or_height<W: Write>(w: &mut W, value: u32) -> io::Result<()> {
    if value < 1 || value > 256 {
        // TODO: this is not very idiomatic yet. Should return an EncodingError and be checked
        // prior to encoding.
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            "Invalid ICO dimensions (width and \
             height must be between 1 and 256)",
        ));
    }
    w.write_u8(if value < 256 { value as u8 } else { 0 })
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use cgmath;
use cgmath::FixedArray;
use gfx;
use grid;
use grid::Grid;
use scene;

#[shader_param]
struct Param<R: gfx::Resources> {
    mvp: [[f32; 4]; 4],
    color: [f32; 4],
    _dummy: PhantomData<R>,
}

#[vertex_format]
#[derive(Clone, Copy)]
struct Vertex {
    position: [f32; 2],
}

impl Vertex {
    pub fn new(x: f32, y: f32) -> Vertex {
        Vertex {
            position: [x, y],
        }
    }
}

static VERTEX_SRC: &'static [u8] = b"
    #version 120

    uniform mat4 mvp;
    attribute vec2 position;

    void main() {
        gl_Position = mvp * vec4(position, 0.0, 1.0);
        gl_PointSize = 2.0;
    }
";

static FRAGMENT_SRC: &'static [u8] = b"
    #version 120

    uniform vec4 color;

    void main() {
        gl_FragColor = color;
    }
";

pub use grid::quad::{Coordinate, Direction};

pub struct Field<R: gfx::Resources> {
    pub node: scene::NodeId<f32>,
    pub grid: grid::quad::Grid,
    batch: gfx::batch::OwnedBatch<Param<R>>,
}

impl<R: gfx::Resources> Field<R> {
    pub fn new<F: gfx::Factory<R>>(factory: &mut F,
               node: scene::NodeId<f32>, size: f32, area: f32,
               color: (f32, f32, f32, f32))
               -> Field<R> {
        use gfx::traits::FactoryExt;
        let grid = grid::quad::Grid::new(size);
        let area = [[-area, -area, 0.0], [area, area, 0.0]];
        let vertices = grid.fold_edges_in_area(&area, Vec::new(), |mut u, a, b, _, _| {
            u.push(Vertex::new(a[0], a[1]));
            u.push(Vertex::new(b[0], b[1]));
            u
        });
        let mesh = factory.create_mesh(&vertices);
        let program = factory.link_program(VERTEX_SRC, FRAGMENT_SRC).unwrap();
        let mut batch = gfx::batch::OwnedBatch::new(mesh, program, Param {
            mvp: [[0.0; 4]; 4],
            color: [color.0, color.1, color.2, color.3],
            _dummy: PhantomData,
        }).unwrap();
        batch.state = batch.state.depth(gfx::state::Comparison::LessEqual, false);
        batch.slice.prim_type = gfx::PrimitiveType::Line;
        Field {
            node: node,
            grid: grid,
            batch: batch,
        }
    }

    pub fn get_center(&self, coord: Coordinate) -> cgmath::Point3<f32> {
        let fixed = self.grid.get_cell_center(coord);
        cgmath::Point3::new(fixed[0], fixed[1], fixed[2])
    }

    pub fn get_cell(&self, position: &cgmath::Point3<f32>) -> Coordinate {
        self.grid.get_coordinate(position.as_fixed())
    }

    pub fn cast_ray(&self, ray: &cgmath::Ray3<f32>) -> Coordinate {
        use cgmath::{Point, Vector};
        let t = -ray.origin.z / ray.direction.z;
        let p = ray.origin.add_v(&ray.direction.mul_s(t));
        self.get_cell(&p)
    }

    pub fn update_params(&mut self, camera: &scene::Camera<f32>, world: &scene::World<f32>) {
        use cgmath::{Matrix, ToMatrix4, Transform};
        use scene::base::World;
        let mx_proj = camera.projection.to_matrix4();
        let model_view = world.get_transform(&camera.node).invert().unwrap()
                              .concat(&world.get_transform(&self.node));
        self.batch.param.mvp = mx_proj.mul_m(&model_view.to_matrix4()).into_fixed();
    }

    pub fn draw<S: gfx::Stream<R>>(&self, stream: &mut S) {
        stream.draw(&self.batch).unwrap();
    }
}
<commit_msg>Added 150 for osx<commit_after>use std::marker::PhantomData;
use cgmath;
use cgmath::FixedArray;
use gfx;
use grid;
use grid::Grid;
use scene;

#[shader_param]
struct Param<R: gfx::Resources> {
    mvp: [[f32; 4]; 4],
    color: [f32; 4],
    _dummy: PhantomData<R>,
}

#[vertex_format]
#[derive(Clone, Copy)]
struct Vertex {
    position: [f32; 2],
}

impl Vertex {
    pub fn new(x: f32, y: f32) -> Vertex {
        Vertex {
            position: [x, y],
        }
    }
}

#[cfg(not(target_os = "macos"))]
static VERTEX_SRC: &'static [u8] = b"
    #version 120

    uniform mat4 mvp;
    attribute vec2 position;

    void main() {
        gl_Position = mvp * vec4(position, 0.0, 1.0);
        gl_PointSize = 2.0;
    }
";

#[cfg(target_os = "macos")]
static VERTEX_SRC: &'static [u8] = b"
    #version 150

    uniform mat4 mvp;
    in vec2 position;

    void main() {
        gl_Position = mvp * vec4(position, 0.0, 1.0);
        gl_PointSize = 2.0;
    }
";

#[cfg(not(target_os = "macos"))]
static FRAGMENT_SRC: &'static [u8] = b"
    #version 120

    uniform vec4 color;

    void main() {
        gl_FragColor = color;
    }
";

#[cfg(target_os = "macos")]
static FRAGMENT_SRC: &'static [u8] = b"
    #version 150

    uniform vec4 color;
    out vec4 f_color;

    void main() {
        f_color = color;
    }
";

pub use grid::quad::{Coordinate, Direction};

pub struct Field<R: gfx::Resources> {
    pub node: scene::NodeId<f32>,
    pub grid: grid::quad::Grid,
    batch: gfx::batch::OwnedBatch<Param<R>>,
}

impl<R: gfx::Resources> Field<R> {
    pub fn new<F: gfx::Factory<R>>(factory: &mut F,
               node: scene::NodeId<f32>, size: f32, area: f32,
               color: (f32, f32, f32, f32))
               -> Field<R> {
        use gfx::traits::FactoryExt;
        let grid = grid::quad::Grid::new(size);
        let area = [[-area, -area, 0.0], [area, area, 0.0]];
        let vertices = grid.fold_edges_in_area(&area, Vec::new(), |mut u, a, b, _, _| {
            u.push(Vertex::new(a[0], a[1]));
            u.push(Vertex::new(b[0], b[1]));
            u
        });
        let mesh = factory.create_mesh(&vertices);
        let program = factory.link_program(VERTEX_SRC, FRAGMENT_SRC).unwrap();
        let mut batch = gfx::batch::OwnedBatch::new(mesh, program, Param {
            mvp: [[0.0; 4]; 4],
            color: [color.0, color.1, color.2, color.3],
            _dummy: PhantomData,
        }).unwrap();
        batch.state = batch.state.depth(gfx::state::Comparison::LessEqual, false);
        batch.slice.prim_type = gfx::PrimitiveType::Line;
        Field {
            node: node,
            grid: grid,
            batch: batch,
        }
    }

    pub fn get_center(&self, coord: Coordinate) -> cgmath::Point3<f32> {
        let fixed = self.grid.get_cell_center(coord);
        cgmath::Point3::new(fixed[0], fixed[1], fixed[2])
    }

    pub fn get_cell(&self, position: &cgmath::Point3<f32>) -> Coordinate {
        self.grid.get_coordinate(position.as_fixed())
    }

    pub fn cast_ray(&self, ray: &cgmath::Ray3<f32>) -> Coordinate {
        use cgmath::{Point, Vector};
        let t = -ray.origin.z / ray.direction.z;
        let p = ray.origin.add_v(&ray.direction.mul_s(t));
        self.get_cell(&p)
    }

    pub fn update_params(&mut self, camera: &scene::Camera<f32>, world: &scene::World<f32>) {
        use cgmath::{Matrix, ToMatrix4, Transform};
        use scene::base::World;
        let mx_proj = camera.projection.to_matrix4();
        let model_view = world.get_transform(&camera.node).invert().unwrap()
                              .concat(&world.get_transform(&self.node));
        self.batch.param.mvp = mx_proj.mul_m(&model_view.to_matrix4()).into_fixed();
    }

    pub fn draw<S: gfx::Stream<R>>(&self, stream: &mut S) {
        stream.draw(&self.batch).unwrap();
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Utilities for manipulating the char type

use cmp::Ord;
use option::{None, Option, Some};
use str;
use u32;
use uint;
use unicode;

#[cfg(notest)] use cmp::Eq;

/*
    Lu  Uppercase_Letter    an uppercase letter
    Ll  Lowercase_Letter    a lowercase letter
    Lt  Titlecase_Letter    a digraphic character, with first part uppercase
    Lm  Modifier_Letter     a modifier letter
    Lo  Other_Letter    other letters, including syllables and ideographs
    Mn  Nonspacing_Mark     a nonspacing combining mark (zero advance width)
    Mc  Spacing_Mark    a spacing combining mark (positive advance width)
    Me  Enclosing_Mark  an enclosing combining mark
    Nd  Decimal_Number  a decimal digit
    Nl  Letter_Number   a letterlike numeric character
    No  Other_Number    a numeric character of other type
    Pc  Connector_Punctuation   a connecting punctuation mark, like a tie
    Pd  Dash_Punctuation    a dash or hyphen punctuation mark
    Ps  Open_Punctuation    an opening punctuation mark (of a pair)
    Pe  Close_Punctuation   a closing punctuation mark (of a pair)
    Pi  Initial_Punctuation     an initial quotation mark
    Pf  Final_Punctuation   a final quotation mark
    Po  Other_Punctuation   a punctuation mark of other type
    Sm  Math_Symbol     a symbol of primarily mathematical use
    Sc  Currency_Symbol     a currency sign
    Sk  Modifier_Symbol     a non-letterlike modifier symbol
    So  Other_Symbol    a symbol of other type
    Zs  Space_Separator     a space character (of various non-zero widths)
    Zl  Line_Separator  U+2028 LINE SEPARATOR only
    Zp  Paragraph_Separator     U+2029 PARAGRAPH SEPARATOR only
    Cc  Control     a C0 or C1 control code
    Cf  Format  a format control character
    Cs  Surrogate   a surrogate code point
    Co  Private_Use     a private-use character
    Cn  Unassigned  a reserved unassigned code point or a noncharacter
*/

pub use is_alphabetic = unicode::derived_property::Alphabetic;
pub use is_XID_start = unicode::derived_property::XID_Start;
pub use is_XID_continue = unicode::derived_property::XID_Continue;

/**
 * Indicates whether a character is in lower case, defined
 * in terms of the Unicode General Category 'Ll'
 */
#[inline(always)]
pub fn is_lowercase(c: char) -> bool {
    return unicode::general_category::Ll(c);
}

/**
 * Indicates whether a character is in upper case, defined
 * in terms of the Unicode General Category 'Lu'.
 */
#[inline(always)]
pub fn is_uppercase(c: char) -> bool {
    return unicode::general_category::Lu(c);
}

/**
 * Indicates whether a character is whitespace. Whitespace is defined in
 * terms of the Unicode General Categories 'Zs', 'Zl', 'Zp'
 * additional 'Cc'-category control codes in the range [0x09, 0x0d]
 */
#[inline(always)]
pub fn is_whitespace(c: char) -> bool {
    return ('\x09' <= c && c <= '\x0d')
        || unicode::general_category::Zs(c)
        || unicode::general_category::Zl(c)
        || unicode::general_category::Zp(c);
}

/**
 * Indicates whether a character is alphanumeric. Alphanumericness is
 * defined in terms of the Unicode General Categories 'Nd', 'Nl', 'No'
 * and the Derived Core Property 'Alphabetic'.
 */
#[inline(always)]
pub fn is_alphanumeric(c: char) -> bool {
    return unicode::derived_property::Alphabetic(c) ||
        unicode::general_category::Nd(c) ||
        unicode::general_category::Nl(c) ||
        unicode::general_category::No(c);
}

/// Indicates whether the character is numeric (Nd, Nl, or No)
#[inline(always)]
pub fn is_digit(c: char) -> bool {
    return unicode::general_category::Nd(c) ||
        unicode::general_category::Nl(c) ||
        unicode::general_category::No(c);
}

/**
 * Checks if a character parses as a numeric digit in the given radix.
 * Compared to `is_digit()`, this function only recognizes the
 * characters `0-9`, `a-z` and `A-Z`.
 *
 * Returns `true` if `c` is a valid digit under `radix`, and `false`
 * otherwise.
 *
 * Fails if given a `radix` > 36.
 *
 * Note: This just wraps `to_digit()`.
 */
#[inline(always)]
pub fn is_digit_radix(c: char, radix: uint) -> bool {
    match to_digit(c, radix) {
        Some(_) => true,
        None    => false
    }
}

/**
 * Convert a char to the corresponding digit.
 *
 * # Return value
 *
 * If `c` is between '0' and '9', the corresponding value
 * between 0 and 9. If `c` is 'a' or 'A', 10. If `c` is
 * 'b' or 'B', 11, etc. Returns none if the char does not
 * refer to a digit in the given radix.
 *
 * # Failure
 * Fails if given a `radix` outside the range `[0..36]`.
 */
#[inline]
pub fn to_digit(c: char, radix: uint) -> Option<uint> {
    if radix > 36 {
        fail!(fmt!("to_digit: radix %? is to high (maximum 36)", radix));
    }
    let val = match c {
      '0' .. '9' => c as uint - ('0' as uint),
      'a' .. 'z' => c as uint + 10u - ('a' as uint),
      'A' .. 'Z' => c as uint + 10u - ('A' as uint),
      _ => return None
    };
    if val < radix { Some(val) }
    else { None }
}

/**
 * Converts a number to the character representing it.
 *
 * Returns `Some(char)` if `num` represents one digit under `radix`,
 * using one character of `0-9` or `a-z`, or `None` if it doesn't.
 *
 * Fails if given an `radix` > 36.
 */
#[inline]
pub fn from_digit(num: uint, radix: uint) -> Option<char> {
    if radix > 36 {
        fail!(fmt!("from_digit: radix %? is to high (maximum 36)", num));
    }
    if num < radix {
        if num < 10 {
            Some(('0' as uint + num) as char)
        } else {
            Some(('a' as uint + num - 10u) as char)
        }
    } else {
        None
    }
}

/**
 * Return the hexadecimal unicode escape of a char.
 *
 * The rules are as follows:
 *
 *   - chars in [0,0xff] get 2-digit escapes: `\\xNN`
 *   - chars in [0x100,0xffff] get 4-digit escapes: `\\uNNNN`
 *   - chars above 0x10000 get 8-digit escapes: `\\UNNNNNNNN`
 */
pub fn escape_unicode(c: char) -> ~str {
    let s = u32::to_str_radix(c as u32, 16u);
    let (c, pad) = (if c <= '\xff' { ('x', 2u) }
                    else if c <= '\uffff' { ('u', 4u) }
                    else { ('U', 8u) });
    assert!(str::len(s) <= pad);
    let mut out = ~"\\";
    str::push_str(&mut out, str::from_char(c));
    for uint::range(str::len(s), pad) |_i|
        { str::push_str(&mut out, ~"0"); }
    str::push_str(&mut out, s);
    out
}

/**
 * Return a 'default' ASCII and C++11-like char-literal escape of a char.
 *
 * The default is chosen with a bias toward producing literals that are
 * legal in a variety of languages, including C++11 and similar C-family
 * languages. The exact rules are:
 *
 *   - Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively.
 *   - Single-quote, double-quote and backslash chars are backslash-escaped.
 *   - Any other chars in the range [0x20,0x7e] are not escaped.
 *   - Any other chars are given hex unicode escapes; see `escape_unicode`.
 */
pub fn escape_default(c: char) -> ~str {
    match c {
      '\t' => ~"\\t",
      '\r' => ~"\\r",
      '\n' => ~"\\n",
      '\\' => ~"\\\\",
      '\'' => ~"\\'",
      '"'  => ~"\\\"",
      '\x20' .. '\x7e' => str::from_char(c),
      _ => escape_unicode(c)
    }
}

/// Returns the amount of bytes this character would need if encoded in utf8
pub fn len_utf8_bytes(c: char) -> uint {
    static max_one_b: uint = 128u;
    static max_two_b: uint = 2048u;
    static max_three_b: uint = 65536u;
    static max_four_b: uint = 2097152u;

    let code = c as uint;
    if code < max_one_b { 1u }
    else if code < max_two_b { 2u }
    else if code < max_three_b { 3u }
    else if code < max_four_b { 4u }
    else { fail!(~"invalid character!") }
}

#[cfg(notest)]
impl Eq for char {
    #[inline(always)]
    fn eq(&self, other: &char) -> bool { (*self) == (*other) }
    #[inline(always)]
    fn ne(&self, other: &char) -> bool { (*self) != (*other) }
}

#[cfg(notest)]
impl Ord for char {
    #[inline(always)]
    fn lt(&self, other: &char) -> bool { *self < *other }
    #[inline(always)]
    fn le(&self, other: &char) -> bool { *self <= *other }
    #[inline(always)]
    fn gt(&self, other: &char) -> bool { *self > *other }
    #[inline(always)]
    fn ge(&self, other: &char) -> bool { *self >= *other }
}

#[test]
fn test_is_lowercase() {
    assert!(is_lowercase('a'));
    assert!(is_lowercase('ö'));
    assert!(is_lowercase('ß'));
    assert!(!is_lowercase('Ü'));
    assert!(!is_lowercase('P'));
}

#[test]
fn test_is_uppercase() {
    assert!(!is_uppercase('h'));
    assert!(!is_uppercase('ä'));
    assert!(!is_uppercase('ß'));
    assert!(is_uppercase('Ö'));
    assert!(is_uppercase('T'));
}

#[test]
fn test_is_whitespace() {
    assert!(is_whitespace(' '));
    assert!(is_whitespace('\u2007'));
    assert!(is_whitespace('\t'));
    assert!(is_whitespace('\n'));

    assert!(!is_whitespace('a'));
    assert!(!is_whitespace('_'));
    assert!(!is_whitespace('\u0000'));
}

#[test]
fn test_to_digit() {
    assert_eq!(to_digit('0', 10u), Some(0u));
    assert_eq!(to_digit('1', 2u), Some(1u));
    assert_eq!(to_digit('2', 3u), Some(2u));
    assert_eq!(to_digit('9', 10u), Some(9u));
    assert_eq!(to_digit('a', 16u), Some(10u));
    assert_eq!(to_digit('A', 16u), Some(10u));
    assert_eq!(to_digit('b', 16u), Some(11u));
    assert_eq!(to_digit('B', 16u), Some(11u));
    assert_eq!(to_digit('z', 36u), Some(35u));
    assert_eq!(to_digit('Z', 36u), Some(35u));

    assert!(to_digit(' ', 10u).is_none());
    assert!(to_digit('$', 36u).is_none());
}

#[test]
fn test_is_digit() {
   assert!(is_digit('2'));
   assert!(is_digit('7'));
   assert!(! is_digit('c'));
   assert!(! is_digit('i'));
   assert!(! is_digit('z'));
   assert!(! is_digit('Q'));
}

#[test]
fn test_escape_default() {
    assert_eq!(escape_default('\n'), ~"\\n");
    assert_eq!(escape_default('\r'), ~"\\r");
    assert_eq!(escape_default('\''), ~"\\'");
    assert_eq!(escape_default('"'), ~"\\\"");
    assert_eq!(escape_default(' '), ~" ");
    assert_eq!(escape_default('a'), ~"a");
    assert_eq!(escape_default('~'), ~"~");
    assert_eq!(escape_default('\x00'), ~"\\x00");
    assert_eq!(escape_default('\x1f'), ~"\\x1f");
    assert_eq!(escape_default('\x7f'), ~"\\x7f");
    assert_eq!(escape_default('\xff'), ~"\\xff");
    assert_eq!(escape_default('\u011b'), ~"\\u011b");
    assert_eq!(escape_default('\U0001d4b6'), ~"\\U0001d4b6");
}

#[test]
fn test_escape_unicode() {
    assert_eq!(escape_unicode('\x00'), ~"\\x00");
    assert_eq!(escape_unicode('\n'), ~"\\x0a");
    assert_eq!(escape_unicode(' '), ~"\\x20");
    assert_eq!(escape_unicode('a'), ~"\\x61");
    assert_eq!(escape_unicode('\u011b'), ~"\\u011b");
    assert_eq!(escape_unicode('\U0001d4b6'), ~"\\U0001d4b6");
}
<commit_msg>char: fix unused import warning<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Utilities for manipulating the char type

#[cfg(notest)]
use cmp::Ord;
use option::{None, Option, Some};
use str;
use u32;
use uint;
use unicode;

#[cfg(notest)] use cmp::Eq;

/*
    Lu  Uppercase_Letter    an uppercase letter
    Ll  Lowercase_Letter    a lowercase letter
    Lt  Titlecase_Letter    a digraphic character, with first part uppercase
    Lm  Modifier_Letter     a modifier letter
    Lo  Other_Letter    other letters, including syllables and ideographs
    Mn  Nonspacing_Mark     a nonspacing combining mark (zero advance width)
    Mc  Spacing_Mark    a spacing combining mark (positive advance width)
    Me  Enclosing_Mark  an enclosing combining mark
    Nd  Decimal_Number  a decimal digit
    Nl  Letter_Number   a letterlike numeric character
    No  Other_Number    a numeric character of other type
    Pc  Connector_Punctuation   a connecting punctuation mark, like a tie
    Pd  Dash_Punctuation    a dash or hyphen punctuation mark
    Ps  Open_Punctuation    an opening punctuation mark (of a pair)
    Pe  Close_Punctuation   a closing punctuation mark (of a pair)
    Pi  Initial_Punctuation     an initial quotation mark
    Pf  Final_Punctuation   a final quotation mark
    Po  Other_Punctuation   a punctuation mark of other type
    Sm  Math_Symbol     a symbol of primarily mathematical use
    Sc  Currency_Symbol     a currency sign
    Sk  Modifier_Symbol     a non-letterlike modifier symbol
    So  Other_Symbol    a symbol of other type
    Zs  Space_Separator     a space character (of various non-zero widths)
    Zl  Line_Separator  U+2028 LINE SEPARATOR only
    Zp  Paragraph_Separator     U+2029 PARAGRAPH SEPARATOR only
    Cc  Control     a C0 or C1 control code
    Cf  Format  a format control character
    Cs  Surrogate   a surrogate code point
    Co  Private_Use     a private-use character
    Cn  Unassigned  a reserved unassigned code point or a noncharacter
*/

pub use is_alphabetic = unicode::derived_property::Alphabetic;
pub use is_XID_start = unicode::derived_property::XID_Start;
pub use is_XID_continue = unicode::derived_property::XID_Continue;

/**
 * Indicates whether a character is in lower case, defined
 * in terms of the Unicode General Category 'Ll'
 */
#[inline(always)]
pub fn is_lowercase(c: char) -> bool {
    return unicode::general_category::Ll(c);
}

/**
 * Indicates whether a character is in upper case, defined
 * in terms of the Unicode General Category 'Lu'.
 */
#[inline(always)]
pub fn is_uppercase(c: char) -> bool {
    return unicode::general_category::Lu(c);
}

/**
 * Indicates whether a character is whitespace. Whitespace is defined in
 * terms of the Unicode General Categories 'Zs', 'Zl', 'Zp'
 * additional 'Cc'-category control codes in the range [0x09, 0x0d]
 */
#[inline(always)]
pub fn is_whitespace(c: char) -> bool {
    return ('\x09' <= c && c <= '\x0d')
        || unicode::general_category::Zs(c)
        || unicode::general_category::Zl(c)
        || unicode::general_category::Zp(c);
}

/**
 * Indicates whether a character is alphanumeric. Alphanumericness is
 * defined in terms of the Unicode General Categories 'Nd', 'Nl', 'No'
 * and the Derived Core Property 'Alphabetic'.
 */
#[inline(always)]
pub fn is_alphanumeric(c: char) -> bool {
    return unicode::derived_property::Alphabetic(c) ||
        unicode::general_category::Nd(c) ||
        unicode::general_category::Nl(c) ||
        unicode::general_category::No(c);
}

/// Indicates whether the character is numeric (Nd, Nl, or No)
#[inline(always)]
pub fn is_digit(c: char) -> bool {
    return unicode::general_category::Nd(c) ||
        unicode::general_category::Nl(c) ||
        unicode::general_category::No(c);
}

/**
 * Checks if a character parses as a numeric digit in the given radix.
 * Compared to `is_digit()`, this function only recognizes the
 * characters `0-9`, `a-z` and `A-Z`.
 *
 * Returns `true` if `c` is a valid digit under `radix`, and `false`
 * otherwise.
 *
 * Fails if given a `radix` > 36.
 *
 * Note: This just wraps `to_digit()`.
 */
#[inline(always)]
pub fn is_digit_radix(c: char, radix: uint) -> bool {
    match to_digit(c, radix) {
        Some(_) => true,
        None    => false
    }
}

/**
 * Convert a char to the corresponding digit.
 *
 * # Return value
 *
 * If `c` is between '0' and '9', the corresponding value
 * between 0 and 9. If `c` is 'a' or 'A', 10. If `c` is
 * 'b' or 'B', 11, etc. Returns none if the char does not
 * refer to a digit in the given radix.
 *
 * # Failure
 * Fails if given a `radix` outside the range `[0..36]`.
 */
#[inline]
pub fn to_digit(c: char, radix: uint) -> Option<uint> {
    if radix > 36 {
        fail!(fmt!("to_digit: radix %? is to high (maximum 36)", radix));
    }
    let val = match c {
      '0' .. '9' => c as uint - ('0' as uint),
      'a' .. 'z' => c as uint + 10u - ('a' as uint),
      'A' .. 'Z' => c as uint + 10u - ('A' as uint),
      _ => return None
    };
    if val < radix { Some(val) }
    else { None }
}

/**
 * Converts a number to the character representing it.
 *
 * Returns `Some(char)` if `num` represents one digit under `radix`,
 * using one character of `0-9` or `a-z`, or `None` if it doesn't.
 *
 * Fails if given an `radix` > 36.
 */
#[inline]
pub fn from_digit(num: uint, radix: uint) -> Option<char> {
    if radix > 36 {
        fail!(fmt!("from_digit: radix %? is to high (maximum 36)", num));
    }
    if num < radix {
        if num < 10 {
            Some(('0' as uint + num) as char)
        } else {
            Some(('a' as uint + num - 10u) as char)
        }
    } else {
        None
    }
}

/**
 * Return the hexadecimal unicode escape of a char.
 *
 * The rules are as follows:
 *
 *   - chars in [0,0xff] get 2-digit escapes: `\\xNN`
 *   - chars in [0x100,0xffff] get 4-digit escapes: `\\uNNNN`
 *   - chars above 0x10000 get 8-digit escapes: `\\UNNNNNNNN`
 */
pub fn escape_unicode(c: char) -> ~str {
    let s = u32::to_str_radix(c as u32, 16u);
    let (c, pad) = (if c <= '\xff' { ('x', 2u) }
                    else if c <= '\uffff' { ('u', 4u) }
                    else { ('U', 8u) });
    assert!(str::len(s) <= pad);
    let mut out = ~"\\";
    str::push_str(&mut out, str::from_char(c));
    for uint::range(str::len(s), pad) |_i|
        { str::push_str(&mut out, ~"0"); }
    str::push_str(&mut out, s);
    out
}

/**
 * Return a 'default' ASCII and C++11-like char-literal escape of a char.
 *
 * The default is chosen with a bias toward producing literals that are
 * legal in a variety of languages, including C++11 and similar C-family
 * languages. The exact rules are:
 *
 *   - Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively.
 *   - Single-quote, double-quote and backslash chars are backslash-escaped.
 *   - Any other chars in the range [0x20,0x7e] are not escaped.
 *   - Any other chars are given hex unicode escapes; see `escape_unicode`.
 */
pub fn escape_default(c: char) -> ~str {
    match c {
      '\t' => ~"\\t",
      '\r' => ~"\\r",
      '\n' => ~"\\n",
      '\\' => ~"\\\\",
      '\'' => ~"\\'",
      '"'  => ~"\\\"",
      '\x20' .. '\x7e' => str::from_char(c),
      _ => escape_unicode(c)
    }
}

/// Returns the amount of bytes this character would need if encoded in utf8
pub fn len_utf8_bytes(c: char) -> uint {
    static max_one_b: uint = 128u;
    static max_two_b: uint = 2048u;
    static max_three_b: uint = 65536u;
    static max_four_b: uint = 2097152u;

    let code = c as uint;
    if code < max_one_b { 1u }
    else if code < max_two_b { 2u }
    else if code < max_three_b { 3u }
    else if code < max_four_b { 4u }
    else { fail!(~"invalid character!") }
}

#[cfg(notest)]
impl Eq for char {
    #[inline(always)]
    fn eq(&self, other: &char) -> bool { (*self) == (*other) }
    #[inline(always)]
    fn ne(&self, other: &char) -> bool { (*self) != (*other) }
}

#[cfg(notest)]
impl Ord for char {
    #[inline(always)]
    fn lt(&self, other: &char) -> bool { *self < *other }
    #[inline(always)]
    fn le(&self, other: &char) -> bool { *self <= *other }
    #[inline(always)]
    fn gt(&self, other: &char) -> bool { *self > *other }
    #[inline(always)]
    fn ge(&self, other: &char) -> bool { *self >= *other }
}

#[test]
fn test_is_lowercase() {
    assert!(is_lowercase('a'));
    assert!(is_lowercase('ö'));
    assert!(is_lowercase('ß'));
    assert!(!is_lowercase('Ü'));
    assert!(!is_lowercase('P'));
}

#[test]
fn test_is_uppercase() {
    assert!(!is_uppercase('h'));
    assert!(!is_uppercase('ä'));
    assert!(!is_uppercase('ß'));
    assert!(is_uppercase('Ö'));
    assert!(is_uppercase('T'));
}

#[test]
fn test_is_whitespace() {
    assert!(is_whitespace(' '));
    assert!(is_whitespace('\u2007'));
    assert!(is_whitespace('\t'));
    assert!(is_whitespace('\n'));

    assert!(!is_whitespace('a'));
    assert!(!is_whitespace('_'));
    assert!(!is_whitespace('\u0000'));
}

#[test]
fn test_to_digit() {
    assert_eq!(to_digit('0', 10u), Some(0u));
    assert_eq!(to_digit('1', 2u), Some(1u));
    assert_eq!(to_digit('2', 3u), Some(2u));
    assert_eq!(to_digit('9', 10u), Some(9u));
    assert_eq!(to_digit('a', 16u), Some(10u));
    assert_eq!(to_digit('A', 16u), Some(10u));
    assert_eq!(to_digit('b', 16u), Some(11u));
    assert_eq!(to_digit('B', 16u), Some(11u));
    assert_eq!(to_digit('z', 36u), Some(35u));
    assert_eq!(to_digit('Z', 36u), Some(35u));

    assert!(to_digit(' ', 10u).is_none());
    assert!(to_digit('$', 36u).is_none());
}

#[test]
fn test_is_digit() {
   assert!(is_digit('2'));
   assert!(is_digit('7'));
   assert!(! is_digit('c'));
   assert!(! is_digit('i'));
   assert!(! is_digit('z'));
   assert!(! is_digit('Q'));
}

#[test]
fn test_escape_default() {
    assert_eq!(escape_default('\n'), ~"\\n");
    assert_eq!(escape_default('\r'), ~"\\r");
    assert_eq!(escape_default('\''), ~"\\'");
    assert_eq!(escape_default('"'), ~"\\\"");
    assert_eq!(escape_default(' '), ~" ");
    assert_eq!(escape_default('a'), ~"a");
    assert_eq!(escape_default('~'), ~"~");
    assert_eq!(escape_default('\x00'), ~"\\x00");
    assert_eq!(escape_default('\x1f'), ~"\\x1f");
    assert_eq!(escape_default('\x7f'), ~"\\x7f");
    assert_eq!(escape_default('\xff'), ~"\\xff");
    assert_eq!(escape_default('\u011b'), ~"\\u011b");
    assert_eq!(escape_default('\U0001d4b6'), ~"\\U0001d4b6");
}

#[test]
fn test_escape_unicode() {
    assert_eq!(escape_unicode('\x00'), ~"\\x00");
    assert_eq!(escape_unicode('\n'), ~"\\x0a");
    assert_eq!(escape_unicode(' '), ~"\\x20");
    assert_eq!(escape_unicode('a'), ~"\\x61");
    assert_eq!(escape_unicode('\u011b'), ~"\\u011b");
    assert_eq!(escape_unicode('\U0001d4b6'), ~"\\U0001d4b6");
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The Rust compiler.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![crate_name = "rustc"]
#![unstable(feature = "rustc_private", issue = "27812")]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/")]
#![cfg_attr(not(stage0), deny(warnings))]

#![feature(associated_consts)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(copy_from_slice)]
#![feature(enumset)]
#![feature(iter_arith)]
#![feature(libc)]
#![feature(nonzero)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(slice_patterns)]
#![feature(staged_api)]
#![feature(step_by)]
#![feature(str_char)]
#![feature(question_mark)]
#![cfg_attr(test, feature(test))]

extern crate arena;
extern crate core;
extern crate flate;
extern crate fmt_macros;
extern crate getopts;
extern crate graphviz;
extern crate libc;
extern crate rbml;
extern crate rustc_back;
extern crate rustc_data_structures;
extern crate serialize;
extern crate collections;
extern crate rustc_const_math;
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
#[macro_use] #[no_link] extern crate rustc_bitflags;

extern crate serialize as rustc_serialize; // used by deriving

#[cfg(test)]
extern crate test;

#[macro_use]
mod macros;

// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
pub mod diagnostics;

pub mod cfg;
pub mod dep_graph;
pub mod hir;
pub mod infer;
pub mod lint;

pub mod middle {
    pub mod astconv_util;
    pub mod expr_use_visitor; // STAGE0: increase glitch immunity
    pub mod const_val;
    pub mod const_qualif;
    pub mod cstore;
    pub mod dataflow;
    pub mod dead;
    pub mod dependency_format;
    pub mod effect;
    pub mod entry;
    pub mod free_region;
    pub mod intrinsicck;
    pub mod lang_items;
    pub mod liveness;
    pub mod mem_categorization;
    pub mod privacy;
    pub mod reachable;
    pub mod region;
    pub mod recursion_limit;
    pub mod resolve_lifetime;
    pub mod stability;
    pub mod svh;
    pub mod weak_lang_items;
}

pub mod mir {
    pub mod repr;
    pub mod tcx;
    pub mod visit;
    pub mod transform;
    pub mod mir_map;
}

pub mod session;
pub mod traits;
pub mod ty;

pub mod util {
    pub use rustc_back::sha2;

    pub mod common;
    pub mod ppaux;
    pub mod nodemap;
    pub mod num;
    pub mod fs;
}

// A private module so that macro-expanded idents like
// `::rustc::lint::Lint` will also work in `rustc` itself.
//
// `libstd` uses the same trick.
#[doc(hidden)]
mod rustc {
    pub use lint;
}

// FIXME(#27438): right now the unit tests of librustc don't refer to any actual
//                functions generated in librustc_data_structures (all
//                references are through generic functions), but statics are
//                referenced from time to time. Due to this bug we won't
//                actually correctly link in the statics unless we also
//                reference a function, so be sure to reference a dummy
//                function.
#[test]
fn noop() {
    rustc_data_structures::__noop_fix_for_27438();
}

// Build the diagnostics array at the end so that the metadata includes error use sites.
__build_diagnostic_array! { librustc, DIAGNOSTICS }
<commit_msg>remove svh module<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The Rust compiler.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![crate_name = "rustc"]
#![unstable(feature = "rustc_private", issue = "27812")]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/")]
#![cfg_attr(not(stage0), deny(warnings))]

#![feature(associated_consts)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(copy_from_slice)]
#![feature(enumset)]
#![feature(iter_arith)]
#![feature(libc)]
#![feature(nonzero)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(slice_patterns)]
#![feature(staged_api)]
#![feature(step_by)]
#![feature(str_char)]
#![feature(question_mark)]
#![cfg_attr(test, feature(test))]

extern crate arena;
extern crate core;
extern crate flate;
extern crate fmt_macros;
extern crate getopts;
extern crate graphviz;
extern crate libc;
extern crate rbml;
extern crate rustc_back;
extern crate rustc_data_structures;
extern crate serialize;
extern crate collections;
extern crate rustc_const_math;
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
#[macro_use] #[no_link] extern crate rustc_bitflags;

extern crate serialize as rustc_serialize; // used by deriving

#[cfg(test)]
extern crate test;

#[macro_use]
mod macros;

// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
pub mod diagnostics;

pub mod cfg;
pub mod dep_graph;
pub mod hir;
pub mod infer;
pub mod lint;

pub mod middle {
    pub mod astconv_util;
    pub mod expr_use_visitor; // STAGE0: increase glitch immunity
    pub mod const_val;
    pub mod const_qualif;
    pub mod cstore;
    pub mod dataflow;
    pub mod dead;
    pub mod dependency_format;
    pub mod effect;
    pub mod entry;
    pub mod free_region;
    pub mod intrinsicck;
    pub mod lang_items;
    pub mod liveness;
    pub mod mem_categorization;
    pub mod privacy;
    pub mod reachable;
    pub mod region;
    pub mod recursion_limit;
    pub mod resolve_lifetime;
    pub mod stability;
    pub mod weak_lang_items;
}

pub mod mir {
    pub mod repr;
    pub mod tcx;
    pub mod visit;
    pub mod transform;
    pub mod mir_map;
}

pub mod session;
pub mod traits;
pub mod ty;

pub mod util {
    pub use rustc_back::sha2;

    pub mod common;
    pub mod ppaux;
    pub mod nodemap;
    pub mod num;
    pub mod fs;
}

// A private module so that macro-expanded idents like
// `::rustc::lint::Lint` will also work in `rustc` itself.
//
// `libstd` uses the same trick.
#[doc(hidden)]
mod rustc {
    pub use lint;
}

// FIXME(#27438): right now the unit tests of librustc don't refer to any actual
//                functions generated in librustc_data_structures (all
//                references are through generic functions), but statics are
//                referenced from time to time. Due to this bug we won't
//                actually correctly link in the statics unless we also
//                reference a function, so be sure to reference a dummy
//                function.
#[test]
fn noop() {
    rustc_data_structures::__noop_fix_for_27438();
}

// Build the diagnostics array at the end so that the metadata includes error use sites.
__build_diagnostic_array! { librustc, DIAGNOSTICS }
<|endoftext|>


<commit_before>/// Represents the players in a Tic-tac-toe game.
#[deriving(Clone, Show)]
pub enum Mark {
  X, O
}

impl Mark {
  /// Returns the opposite mark.
  pub fn opposite(self) -> Mark {
    match self {
      X => O,
      O => X
    }
  }
}

/// Represents a line of the Tic-tac-toe board. A line consists of three cells.
struct PlayLine {
  cells: [Option<Mark>, ..3]
}

impl PlayLine {
  /// Determines if this line counts as a win. Returns the winner wrapped in an
  /// Option, with None meaning that this line is not a winning one.
  pub fn is_win(&self) -> Option<Mark> {
    let (xs, os) = self.cells.iter().fold((0, 0), |(xs, os), &place| {
      match place {
        Some(X) => (xs + 1, os),
        Some(O) => (xs, os + 1),
        None    => (xs, os)
      }
    });
    if xs == 3 {
      Some(X)
    } else if os == 3 {
      Some(O)
    } else {
      None
    }
  }
}

/// Stores the board data associated with a game of Tic-tac-toe.
pub struct PlayField {
  cells: [Option<Mark>, ..9]
}

impl PlayField {
  pub fn new() -> PlayField {
    PlayField {
      cells: [None, ..9]
    }
  }

  /// Returns the number of occupied cells.
  pub fn occupied_count(&self) -> int {
    self.cells.iter().fold(0, |s, mark| if mark.is_some() { s + 1 } else { s })
  }

  /// Returns an iterator over the `PlayLine`s in this field.
  pub fn lines<'a>(&'a self) -> LineIterator<'a> {
    LineIterator::from_field(self)
  }

  fn horizontal_line(&self, row: uint) -> Option<PlayLine> {
    PlayField::map_xy(0, row).map(|ix| PlayLine {
      // there's probably a trick to do this with a slice
      cells: [self.cells[ix], self.cells[ix + 1], self.cells[ix + 2]]
    })
  }

  fn vertical_line(&self, col: uint) -> Option<PlayLine> {
    PlayField::map_xy(col, 0).map(|ix| PlayLine {
      cells: [self.cells[ix], self.cells[ix + 3], self.cells[ix + 6]]
    })
  }

  fn ltr_diagonal_line(&self) -> PlayLine {
    PlayLine {
      cells: [self.cells[0], self.cells[4], self.cells[8]]
    }
  }

  fn rtl_diagonal_line(&self) -> PlayLine {
    PlayLine {
      cells: [self.cells[2], self.cells[4], self.cells[6]]
    }
  }

  pub fn map_xy(x: uint, y: uint) -> Option<uint> {
    if y < 3 && y < 3 {
      Some(y * 3 + x)
    } else {
      None
    }
  }

  pub fn get_cell_xy(&self, x: uint, y: uint) -> Option<Option<Mark>> {
    PlayField::map_xy(x, y).map(|ix| self.cells[ix])
  }

  pub fn get_mut_cell_xy<'a>(&'a mut self, x: uint, y: uint) -> Option<&'a mut Option<Mark>> {
    match PlayField::map_xy(x, y) {
      Some(ix) => Some(&mut self.cells[ix]),
      None     => None
    }
  }
}

/// Represents an on-screen area where a Tic-tac-toe board can be interacted
/// with.
pub struct FieldArea {
  pub x: int,
  pub y: int,
  pub w: int,
  pub h: int
}

impl FieldArea {
  pub fn from_rect(rect: &::sdl2::rect::Rect) -> FieldArea {
    FieldArea {
      x: rect.x as int, y: rect.y as int,
      w: rect.w as int, h: rect.h as int
    }
  }

  /// Returns the width of an individual cell.
  pub fn cell_width(&self) -> int {
    self.w / 3
  }

  /// Returns the height of an individual cell.
  pub fn cell_height(&self) -> int {
    self.h / 3
  }

  /// Computes the row at a given on-screen Y-coordinate.
  pub fn unproject_row(&self, y: int) -> Option<int> {
    if y >= self.y {
      match (y - self.y) / self.cell_height() {
        ix if ix > 2 => None,
        ix           => Some(ix)
      }
    } else {
      None
    }
  }

  /// Computes the column at a given on-screen X-coordinate.
  pub fn unproject_col(&self, x: int) -> Option<int> {
    if x >= self.x {
      match (x - self.x) / self.cell_width() {
        ix if ix > 2 => None,
        ix           => Some(ix)
      }
    } else {
      None
    }
  }

  /// Computes the given row and column given on-screen X and Y coordinates.
  pub fn unproject(&self, x: int, y: int) -> Option<(int, int)> {
    let row = match self.unproject_row(y) {
      Some(row) => row,
      None      => return None
    };
    let col = match self.unproject_col(x) {
      Some(col) => col,
      None      => return None
    };
    Some((row, col))
  }

  /// Computes the on-screen X and Y coordinates for a given row and column.
  pub fn project(&self, row: int, col: int) -> ::sdl2::rect::Point {
    let x = (self.x + col * self.cell_width()) as i32;
    let y = (self.y + row * self.cell_height()) as i32;
    ::sdl2::rect::Point::new(x, y)
  }
}

enum LineIteratorState {
  Row(uint),
  Column(uint),
  LtrDiagonal,
  RtlDiagonal,
  Finished
}

struct LineIterator<'a> {
  field: &'a PlayField,
  state: LineIteratorState
}

impl<'a> LineIterator<'a> {
  fn from_field<'a>(f: &'a PlayField) -> LineIterator<'a> {
    LineIterator {
      field: f,
      state: Row(0)
    }
  }
}

impl<'a> Iterator<PlayLine> for LineIterator<'a> {
  fn next(&mut self) -> Option<PlayLine> {
    match self.state {
      Row(place) => {
        self.state = if place + 1 < 3 {
          Row(place + 1)
        } else {
          Column(0)
        };
        self.field.horizontal_line(place)
      },
      Column(place) => {
        self.state = if place + 1 < 3 {
          Column(place + 1)
        } else {
          LtrDiagonal
        };
        self.field.vertical_line(place)
      },
      LtrDiagonal => {
        self.state = RtlDiagonal;
        Some(self.field.ltr_diagonal_line())
      },
      RtlDiagonal => {
        self.state = Finished;
        Some(self.field.rtl_diagonal_line())
      },
      Finished => None
    }
  }
}
<commit_msg>Rename LineIterator to Lines for stdlib consistency<commit_after>/// Represents the players in a Tic-tac-toe game.
#[deriving(Clone, Show)]
pub enum Mark {
  X, O
}

impl Mark {
  /// Returns the opposite mark.
  pub fn opposite(self) -> Mark {
    match self {
      X => O,
      O => X
    }
  }
}

/// Represents a line of the Tic-tac-toe board. A line consists of three cells.
struct PlayLine {
  cells: [Option<Mark>, ..3]
}

impl PlayLine {
  /// Determines if this line counts as a win. Returns the winner wrapped in an
  /// Option, with None meaning that this line is not a winning one.
  pub fn is_win(&self) -> Option<Mark> {
    let (xs, os) = self.cells.iter().fold((0, 0), |(xs, os), &place| {
      match place {
        Some(X) => (xs + 1, os),
        Some(O) => (xs, os + 1),
        None    => (xs, os)
      }
    });
    if xs == 3 {
      Some(X)
    } else if os == 3 {
      Some(O)
    } else {
      None
    }
  }
}

/// Stores the board data associated with a game of Tic-tac-toe.
pub struct PlayField {
  cells: [Option<Mark>, ..9]
}

impl PlayField {
  pub fn new() -> PlayField {
    PlayField {
      cells: [None, ..9]
    }
  }

  /// Returns the number of occupied cells.
  pub fn occupied_count(&self) -> int {
    self.cells.iter().fold(0, |s, mark| if mark.is_some() { s + 1 } else { s })
  }

  /// Returns an iterator over the `PlayLine`s in this field.
  pub fn lines<'a>(&'a self) -> Lines<'a> {
    Lines::from_field(self)
  }

  fn horizontal_line(&self, row: uint) -> Option<PlayLine> {
    PlayField::map_xy(0, row).map(|ix| PlayLine {
      // there's probably a trick to do this with a slice
      cells: [self.cells[ix], self.cells[ix + 1], self.cells[ix + 2]]
    })
  }

  fn vertical_line(&self, col: uint) -> Option<PlayLine> {
    PlayField::map_xy(col, 0).map(|ix| PlayLine {
      cells: [self.cells[ix], self.cells[ix + 3], self.cells[ix + 6]]
    })
  }

  fn ltr_diagonal_line(&self) -> PlayLine {
    PlayLine {
      cells: [self.cells[0], self.cells[4], self.cells[8]]
    }
  }

  fn rtl_diagonal_line(&self) -> PlayLine {
    PlayLine {
      cells: [self.cells[2], self.cells[4], self.cells[6]]
    }
  }

  pub fn map_xy(x: uint, y: uint) -> Option<uint> {
    if y < 3 && y < 3 {
      Some(y * 3 + x)
    } else {
      None
    }
  }

  pub fn get_cell_xy(&self, x: uint, y: uint) -> Option<Option<Mark>> {
    PlayField::map_xy(x, y).map(|ix| self.cells[ix])
  }

  pub fn get_mut_cell_xy<'a>(&'a mut self, x: uint, y: uint) -> Option<&'a mut Option<Mark>> {
    match PlayField::map_xy(x, y) {
      Some(ix) => Some(&mut self.cells[ix]),
      None     => None
    }
  }
}

/// Represents an on-screen area where a Tic-tac-toe board can be interacted
/// with.
pub struct FieldArea {
  pub x: int,
  pub y: int,
  pub w: int,
  pub h: int
}

impl FieldArea {
  pub fn from_rect(rect: &::sdl2::rect::Rect) -> FieldArea {
    FieldArea {
      x: rect.x as int, y: rect.y as int,
      w: rect.w as int, h: rect.h as int
    }
  }

  /// Returns the width of an individual cell.
  pub fn cell_width(&self) -> int {
    self.w / 3
  }

  /// Returns the height of an individual cell.
  pub fn cell_height(&self) -> int {
    self.h / 3
  }

  /// Computes the row at a given on-screen Y-coordinate.
  pub fn unproject_row(&self, y: int) -> Option<int> {
    if y >= self.y {
      match (y - self.y) / self.cell_height() {
        ix if ix > 2 => None,
        ix           => Some(ix)
      }
    } else {
      None
    }
  }

  /// Computes the column at a given on-screen X-coordinate.
  pub fn unproject_col(&self, x: int) -> Option<int> {
    if x >= self.x {
      match (x - self.x) / self.cell_width() {
        ix if ix > 2 => None,
        ix           => Some(ix)
      }
    } else {
      None
    }
  }

  /// Computes the given row and column given on-screen X and Y coordinates.
  pub fn unproject(&self, x: int, y: int) -> Option<(int, int)> {
    let row = match self.unproject_row(y) {
      Some(row) => row,
      None      => return None
    };
    let col = match self.unproject_col(x) {
      Some(col) => col,
      None      => return None
    };
    Some((row, col))
  }

  /// Computes the on-screen X and Y coordinates for a given row and column.
  pub fn project(&self, row: int, col: int) -> ::sdl2::rect::Point {
    let x = (self.x + col * self.cell_width()) as i32;
    let y = (self.y + row * self.cell_height()) as i32;
    ::sdl2::rect::Point::new(x, y)
  }
}

enum LinesState {
  Row(uint),
  Column(uint),
  LtrDiagonal,
  RtlDiagonal,
  Finished
}

struct Lines<'a> {
  field: &'a PlayField,
  state: LinesState
}

impl<'a> Lines<'a> {
  fn from_field<'a>(f: &'a PlayField) -> Lines<'a> {
    Lines {
      field: f,
      state: Row(0)
    }
  }
}

impl<'a> Iterator<PlayLine> for Lines<'a> {
  fn next(&mut self) -> Option<PlayLine> {
    match self.state {
      Row(place) => {
        self.state = if place + 1 < 3 {
          Row(place + 1)
        } else {
          Column(0)
        };
        self.field.horizontal_line(place)
      },
      Column(place) => {
        self.state = if place + 1 < 3 {
          Column(place + 1)
        } else {
          LtrDiagonal
        };
        self.field.vertical_line(place)
      },
      LtrDiagonal => {
        self.state = RtlDiagonal;
        Some(self.field.ltr_diagonal_line())
      },
      RtlDiagonal => {
        self.state = Finished;
        Some(self.field.rtl_diagonal_line())
      },
      Finished => None
    }
  }
}
<|endoftext|>


<commit_before>use itertools::Itertools;
use std::hash::Hash;
use std::iter::FromIterator;

use generate::{HashIndexer, IndexVertices, IntoTriangles, IntoVertices, Topological, Triangulate};
use graph::geometry::{Attribute, Geometry};
use graph::storage::{EdgeKey, FaceKey, Storage, VertexKey};

#[derive(Clone, Debug)]
pub struct Vertex<T>
where
    T: Attribute,
{
    pub geometry: T,
    pub(super) edge: Option<EdgeKey>,
}

impl<T> Vertex<T>
where
    T: Attribute,
{
    fn new() -> Self {
        Vertex::with_geometry(T::default())
    }

    fn with_geometry(geometry: T) -> Self {
        Vertex {
            geometry: geometry,
            edge: None,
        }
    }
}

#[derive(Clone, Debug)]
pub struct Edge<T>
where
    T: Attribute,
{
    pub geometry: T,
    pub(super) vertex: VertexKey,
    pub(super) opposite: Option<EdgeKey>,
    pub(super) next: Option<EdgeKey>,
    pub(super) face: Option<FaceKey>,
}

impl<T> Edge<T>
where
    T: Attribute,
{
    fn new(vertex: VertexKey) -> Self {
        Edge::with_geometry(vertex, T::default())
    }

    fn with_geometry(vertex: VertexKey, geometry: T) -> Self {
        Edge {
            geometry: geometry,
            vertex: vertex,
            opposite: None,
            next: None,
            face: None,
        }
    }
}

#[derive(Clone, Debug)]
pub struct Face<T>
where
    T: Attribute,
{
    pub geometry: T,
    pub(super) edge: EdgeKey,
}

impl<T> Face<T>
where
    T: Attribute,
{
    fn new(edge: EdgeKey) -> Self {
        Face::with_geometry(edge, T::default())
    }

    fn with_geometry(edge: EdgeKey, geometry: T) -> Self {
        Face {
            geometry: geometry,
            edge: edge,
        }
    }
}

pub struct Mesh<G = u64>
where
    G: Geometry,
{
    pub(super) vertices: Storage<VertexKey, Vertex<G::Vertex>>,
    pub(super) edges: Storage<EdgeKey, Edge<G::Edge>>,
    pub(super) faces: Storage<FaceKey, Face<G::Face>>,
}

impl<G> Mesh<G>
where
    G: Geometry,
{
    pub fn new() -> Self {
        Mesh {
            vertices: Storage::new(),
            edges: Storage::new(),
            faces: Storage::new(),
        }
    }

    pub fn vertex_count(&self) -> usize {
        self.vertices.len()
    }

    pub fn edge_count(&self) -> usize {
        self.edges.len()
    }

    pub fn face_count(&self) -> usize {
        self.faces.len()
    }

    fn insert_vertex(&mut self, geometry: G::Vertex) -> VertexKey {
        self.vertices.insert(Vertex::with_geometry(geometry))
    }

    fn insert_edge(
        &mut self,
        vertices: (VertexKey, VertexKey),
        geometry: G::Edge,
    ) -> Result<EdgeKey, ()> {
        let (a, b) = vertices;
        let ab = (a, b).into();
        let ba = (b, a).into();
        //println!("{:?}", ab);
        let mut edge = Edge::with_geometry(b, geometry);
        if let Some(opposite) = self.edges.get_mut(ba) {
            edge.opposite = Some(ba);
            opposite.opposite = Some(ab);
        }
        self.edges.insert_with_key(ab, edge);
        self.vertices.get_mut(a).unwrap().edge = Some(ab);
        Ok(ab)
    }

    fn connect_edges_in_face(&mut self, face: FaceKey, edges: (EdgeKey, EdgeKey)) {
        let edge = self.edges.get_mut(edges.0).unwrap();
        edge.next = Some(edges.1);
        edge.face = Some(face);
    }

    fn insert_triangle(
        &mut self,
        edges: (EdgeKey, EdgeKey, EdgeKey),
        geometry: G::Face,
    ) -> Result<FaceKey, ()> {
        let (ab, bc, ca) = edges;
        let face = self.faces.insert(Face::with_geometry(ab, geometry));
        self.connect_edges_in_face(face, (ab, bc));
        self.connect_edges_in_face(face, (bc, ca));
        self.connect_edges_in_face(face, (ca, ab));
        Ok(face)
    }
}

impl<G> AsRef<Mesh<G>> for Mesh<G>
where
    G: Geometry,
{
    fn as_ref(&self) -> &Self {
        self
    }
}

impl<G> AsMut<Mesh<G>> for Mesh<G>
where
    G: Geometry,
{
    fn as_mut(&mut self) -> &mut Self {
        self
    }
}

impl<G, T> FromIterator<T> for Mesh<G>
where
    G: Geometry,
    T: IntoTriangles + IntoVertices + Topological,
    T::Vertex: Eq + Hash + Into<G::Vertex>,
{
    fn from_iter<I>(input: I) -> Self
    where
        I: IntoIterator<Item = T>,
    {
        let mut mesh = Mesh::new();
        let (indeces, vertices) = input
            .into_iter()
            .triangulate()
            .index_vertices(HashIndexer::default());
        let vertices = vertices
            .into_iter()
            .map(|vertex| mesh.insert_vertex(vertex.into()))
            .collect::<Vec<_>>();
        for mut triangle in &indeces.into_iter().chunks(3) {
            // Map from the indeces into the original buffers to the keys
            // referring to the vertices in the mesh.
            let (a, b, c) = (
                vertices[triangle.next().unwrap()],
                vertices[triangle.next().unwrap()],
                vertices[triangle.next().unwrap()],
            );
            let (ab, bc, ca) = (
                mesh.insert_edge((a, b), G::Edge::default()).unwrap(),
                mesh.insert_edge((b, c), G::Edge::default()).unwrap(),
                mesh.insert_edge((c, a), G::Edge::default()).unwrap(),
            );
            mesh.insert_triangle((ab, bc, ca), G::Face::default())
                .unwrap();
        }
        mesh
    }
}

#[cfg(test)]
mod tests {
    use r32;
    use generate::*;
    use graph::*;

    #[test]
    fn collect_topology_into_mesh() {
        let mesh = sphere::UVSphere::<f32>::with_unit_radius(3, 2)
            .spatial_polygons() // 6 triangles, 18 vertices.
            .map_vertices(|(x, y, z)| (r32::from(x), r32::from(y), r32::from(z)))
            .triangulate()
            .collect::<Mesh<(r32, r32, r32)>>();

        assert_eq!(5, mesh.vertex_count());
        assert_eq!(18, mesh.edge_count());
        assert_eq!(6, mesh.face_count());
    }
}
<commit_msg>Remove debugging `println!`.<commit_after>use itertools::Itertools;
use std::hash::Hash;
use std::iter::FromIterator;

use generate::{HashIndexer, IndexVertices, IntoTriangles, IntoVertices, Topological, Triangulate};
use graph::geometry::{Attribute, Geometry};
use graph::storage::{EdgeKey, FaceKey, Storage, VertexKey};

#[derive(Clone, Debug)]
pub struct Vertex<T>
where
    T: Attribute,
{
    pub geometry: T,
    pub(super) edge: Option<EdgeKey>,
}

impl<T> Vertex<T>
where
    T: Attribute,
{
    fn new() -> Self {
        Vertex::with_geometry(T::default())
    }

    fn with_geometry(geometry: T) -> Self {
        Vertex {
            geometry: geometry,
            edge: None,
        }
    }
}

#[derive(Clone, Debug)]
pub struct Edge<T>
where
    T: Attribute,
{
    pub geometry: T,
    pub(super) vertex: VertexKey,
    pub(super) opposite: Option<EdgeKey>,
    pub(super) next: Option<EdgeKey>,
    pub(super) face: Option<FaceKey>,
}

impl<T> Edge<T>
where
    T: Attribute,
{
    fn new(vertex: VertexKey) -> Self {
        Edge::with_geometry(vertex, T::default())
    }

    fn with_geometry(vertex: VertexKey, geometry: T) -> Self {
        Edge {
            geometry: geometry,
            vertex: vertex,
            opposite: None,
            next: None,
            face: None,
        }
    }
}

#[derive(Clone, Debug)]
pub struct Face<T>
where
    T: Attribute,
{
    pub geometry: T,
    pub(super) edge: EdgeKey,
}

impl<T> Face<T>
where
    T: Attribute,
{
    fn new(edge: EdgeKey) -> Self {
        Face::with_geometry(edge, T::default())
    }

    fn with_geometry(edge: EdgeKey, geometry: T) -> Self {
        Face {
            geometry: geometry,
            edge: edge,
        }
    }
}

pub struct Mesh<G = u64>
where
    G: Geometry,
{
    pub(super) vertices: Storage<VertexKey, Vertex<G::Vertex>>,
    pub(super) edges: Storage<EdgeKey, Edge<G::Edge>>,
    pub(super) faces: Storage<FaceKey, Face<G::Face>>,
}

impl<G> Mesh<G>
where
    G: Geometry,
{
    pub fn new() -> Self {
        Mesh {
            vertices: Storage::new(),
            edges: Storage::new(),
            faces: Storage::new(),
        }
    }

    pub fn vertex_count(&self) -> usize {
        self.vertices.len()
    }

    pub fn edge_count(&self) -> usize {
        self.edges.len()
    }

    pub fn face_count(&self) -> usize {
        self.faces.len()
    }

    fn insert_vertex(&mut self, geometry: G::Vertex) -> VertexKey {
        self.vertices.insert(Vertex::with_geometry(geometry))
    }

    fn insert_edge(
        &mut self,
        vertices: (VertexKey, VertexKey),
        geometry: G::Edge,
    ) -> Result<EdgeKey, ()> {
        let (a, b) = vertices;
        let ab = (a, b).into();
        let ba = (b, a).into();
        let mut edge = Edge::with_geometry(b, geometry);
        if let Some(opposite) = self.edges.get_mut(ba) {
            edge.opposite = Some(ba);
            opposite.opposite = Some(ab);
        }
        self.edges.insert_with_key(ab, edge);
        self.vertices.get_mut(a).unwrap().edge = Some(ab);
        Ok(ab)
    }

    fn connect_edges_in_face(&mut self, face: FaceKey, edges: (EdgeKey, EdgeKey)) {
        let edge = self.edges.get_mut(edges.0).unwrap();
        edge.next = Some(edges.1);
        edge.face = Some(face);
    }

    fn insert_triangle(
        &mut self,
        edges: (EdgeKey, EdgeKey, EdgeKey),
        geometry: G::Face,
    ) -> Result<FaceKey, ()> {
        let (ab, bc, ca) = edges;
        let face = self.faces.insert(Face::with_geometry(ab, geometry));
        self.connect_edges_in_face(face, (ab, bc));
        self.connect_edges_in_face(face, (bc, ca));
        self.connect_edges_in_face(face, (ca, ab));
        Ok(face)
    }
}

impl<G> AsRef<Mesh<G>> for Mesh<G>
where
    G: Geometry,
{
    fn as_ref(&self) -> &Self {
        self
    }
}

impl<G> AsMut<Mesh<G>> for Mesh<G>
where
    G: Geometry,
{
    fn as_mut(&mut self) -> &mut Self {
        self
    }
}

impl<G, T> FromIterator<T> for Mesh<G>
where
    G: Geometry,
    T: IntoTriangles + IntoVertices + Topological,
    T::Vertex: Eq + Hash + Into<G::Vertex>,
{
    fn from_iter<I>(input: I) -> Self
    where
        I: IntoIterator<Item = T>,
    {
        let mut mesh = Mesh::new();
        let (indeces, vertices) = input
            .into_iter()
            .triangulate()
            .index_vertices(HashIndexer::default());
        let vertices = vertices
            .into_iter()
            .map(|vertex| mesh.insert_vertex(vertex.into()))
            .collect::<Vec<_>>();
        for mut triangle in &indeces.into_iter().chunks(3) {
            // Map from the indeces into the original buffers to the keys
            // referring to the vertices in the mesh.
            let (a, b, c) = (
                vertices[triangle.next().unwrap()],
                vertices[triangle.next().unwrap()],
                vertices[triangle.next().unwrap()],
            );
            let (ab, bc, ca) = (
                mesh.insert_edge((a, b), G::Edge::default()).unwrap(),
                mesh.insert_edge((b, c), G::Edge::default()).unwrap(),
                mesh.insert_edge((c, a), G::Edge::default()).unwrap(),
            );
            mesh.insert_triangle((ab, bc, ca), G::Face::default())
                .unwrap();
        }
        mesh
    }
}

#[cfg(test)]
mod tests {
    use r32;
    use generate::*;
    use graph::*;

    #[test]
    fn collect_topology_into_mesh() {
        let mesh = sphere::UVSphere::<f32>::with_unit_radius(3, 2)
            .spatial_polygons() // 6 triangles, 18 vertices.
            .map_vertices(|(x, y, z)| (r32::from(x), r32::from(y), r32::from(z)))
            .triangulate()
            .collect::<Mesh<(r32, r32, r32)>>();

        assert_eq!(5, mesh.vertex_count());
        assert_eq!(18, mesh.edge_count());
        assert_eq!(6, mesh.face_count());
    }
}
<|endoftext|>


<commit_before>//! Hyphenating iterators.

use std::borrow::Cow;

use unicode_segmentation::UnicodeSegmentation;

use language::{Corpus};
use utilia::{Interspersable, Intersperse};

pub trait Hyphenation<Hyphenator> where Hyphenator : Iterator {
    /// Returns the indices of valid hyphenation points within the given word.
    fn opportunities(self, corp: &Corpus) -> Vec<usize>;

    /// Returns an iterator over orthographic syllables of the given word,
    /// separated by valid hyphenation points.
    ///
    /// Note that, in some orthographies, the syllables of a hyphenated
    /// word are not necessarily substrings of the original word.
    fn hyphenate(self, corp: &Corpus) -> Hyphenator;
}

pub trait FullTextHyphenation<Hyphenator> : Hyphenation<Hyphenator>
    where Hyphenator : Iterator {
    /// Returns the indices of valid hyphenation points within the given text.
    fn fulltext_opportunities(self, corp: &Corpus) -> Vec<usize>;

    /// Returns an iterator over segments of the given text, separated by
    /// valid hyphenation points.
    fn fulltext_hyphenate(self, corp: &Corpus) -> Hyphenator;
}

/// The `Standard` hyphenator iterates over a string, returning slices
/// delimited by string boundaries and valid hyphenation points.
///
/// For individual words, such slices coincide with orthographic syllables.
#[derive(Clone, Debug)]
pub struct Standard<'a> {
    text: &'a str,
    opportunities: Vec<usize>,
    prior: usize,
    i: usize
}

impl<'a> Standard<'a> {
    /// Inserts a soft hyphen at hyphenation points.
    pub fn punctuate(self) -> Intersperse<Self> {
        self.intersperse("\u{ad}")
    }

    /// Inserts a given string at hyphenation points.
    pub fn punctuate_with(self, mark: &'a str) -> Intersperse<Self> {
        self.intersperse(mark)
    }
}

impl<'a> Iterator for Standard<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        let start = self.prior;
        let i = self.i;

        match self.opportunities.get(i) {
            Some(&end) => {
                self.prior = end;
                self.i = i + 1;
                Some(&self.text[start .. end])
            },
            None => {
                if i <= self.opportunities.len() {
                    self.i = i + 1;
                    Some(&self.text[start ..])
                } else {
                    None
                }
            }
        }
    }
}

impl<'a> Hyphenation<Standard<'a>> for &'a str {
    /// Returns the byte indices of valid hyphenation points within the string.
    fn opportunities(self, corp: &Corpus) -> Vec<usize> {
        let (l_min, r_min) = (corp.left_min, corp.right_min);
        let length_min = l_min + r_min;

        if self.chars().count() < length_min {
            return vec![];
        }

        let pts = match corp.exceptions.iter()
                            .filter_map(|exs| exs.score(self))
                            .next() {
                                Some(vec) => Cow::Borrowed(vec),
                                None => Cow::Owned(corp.patterns.score(self))
        };

        self.char_indices().skip(l_min)
            .zip(&pts[l_min - 1 .. pts.len() - r_min + 1])
            .filter(|&(_, p)| p % 2 != 0)
            .map(|((i, _), _)| i)
            .collect()
    }

    /// Returns an iterator over string slices separated by valid hyphenation
    /// points.
    fn hyphenate(self, corp: &Corpus) -> Standard<'a> {
        Standard {
            text: self,
            opportunities: self.opportunities(corp),
            prior: 0,
            i: 0
        }
    }
}

impl<'a> FullTextHyphenation<Standard<'a>> for &'a str {
    fn fulltext_opportunities(self, corp: &Corpus) -> Vec<usize> {
        let (l_min, r_min) = (corp.left_min, corp.right_min);
        let length_min = l_min + r_min;

        if self.chars().count() < length_min {
            return vec![];
        }

        let by_word = self.split_word_bound_indices();
        by_word.flat_map(|(i, word)| {
            let pts = match corp.exceptions.iter()
                                .filter_map(|exs| exs.score(word))
                                .next() {
                                    Some(vec) => Cow::Borrowed(vec),
                                    None => Cow::Owned(corp.patterns.score(word))
            }.into_owned();

            let hyph_length = pts.len();
            let l = l_min;
            let r = if hyph_length >= length_min - 1 { hyph_length + 2 - length_min } else { 0 };

            word.char_indices().skip(l)
                .zip(pts.into_iter().skip(l - 1).take(r))
                .filter(|&(_, p)| p % 2 != 0)
                .map(move |((i1, _), _)| i + i1)
        }).collect()
    }

    fn fulltext_hyphenate(self, corp: &Corpus) -> Standard<'a> {
        Standard {
            text: self,
            opportunities: self.fulltext_opportunities(corp),
            prior: 0,
            i: 0
        }

    }
}
<commit_msg>More meaningful identifiers<commit_after>//! Hyphenating iterators.

use std::borrow::Cow;

use unicode_segmentation::UnicodeSegmentation;

use language::{Corpus};
use utilia::{Interspersable, Intersperse};

pub trait Hyphenation<Hyphenator> where Hyphenator : Iterator {
    /// Returns the indices of valid hyphenation points within the given word.
    fn opportunities(self, corp: &Corpus) -> Vec<usize>;

    /// Returns an iterator over orthographic syllables of the given word,
    /// separated by valid hyphenation points.
    ///
    /// Note that, in some orthographies, the syllables of a hyphenated
    /// word are not necessarily substrings of the original word.
    fn hyphenate(self, corp: &Corpus) -> Hyphenator;
}

pub trait FullTextHyphenation<Hyphenator> : Hyphenation<Hyphenator>
    where Hyphenator : Iterator {
    /// Returns the indices of valid hyphenation points within the given text.
    fn fulltext_opportunities(self, corp: &Corpus) -> Vec<usize>;

    /// Returns an iterator over segments of the given text, separated by
    /// valid hyphenation points.
    fn fulltext_hyphenate(self, corp: &Corpus) -> Hyphenator;
}

/// The `Standard` hyphenator iterates over a string, returning slices
/// delimited by string boundaries and valid hyphenation points.
///
/// For individual words, such slices coincide with orthographic syllables.
#[derive(Clone, Debug)]
pub struct Standard<'a> {
    text: &'a str,
    opportunities: Vec<usize>,
    prior: usize,
    current: usize
}

impl<'a> Standard<'a> {
    /// Inserts a soft hyphen at hyphenation points.
    pub fn punctuate(self) -> Intersperse<Self> {
        self.intersperse("\u{ad}")
    }

    /// Inserts a given string at hyphenation points.
    pub fn punctuate_with(self, mark: &'a str) -> Intersperse<Self> {
        self.intersperse(mark)
    }
}

impl<'a> Iterator for Standard<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        let start = self.prior;
        let current = self.current;

        match self.opportunities.get(current) {
            Some(&end) => {
                self.prior = end;
                self.current = current + 1;
                Some(&self.text[start .. end])
            },
            None => {
                if current <= self.opportunities.len() {
                    self.current = current + 1;
                    Some(&self.text[start ..])
                } else {
                    None
                }
            }
        }
    }
}

impl<'a> Hyphenation<Standard<'a>> for &'a str {
    /// Returns the byte indices of valid hyphenation points within the string.
    fn opportunities(self, corp: &Corpus) -> Vec<usize> {
        let (l_min, r_min) = (corp.left_min, corp.right_min);
        let length_min = l_min + r_min;

        if self.chars().count() < length_min {
            return vec![];
        }

        let pts = match corp.exceptions.iter()
                            .filter_map(|exs| exs.score(self))
                            .next() {
                                Some(vec) => Cow::Borrowed(vec),
                                None => Cow::Owned(corp.patterns.score(self))
        };

        self.char_indices().skip(l_min)
            .zip(&pts[l_min - 1 .. pts.len() - r_min + 1])
            .filter(|&(_, p)| p % 2 != 0)
            .map(|((i, _), _)| i)
            .collect()
    }

    /// Returns an iterator over string slices separated by valid hyphenation
    /// points.
    fn hyphenate(self, corp: &Corpus) -> Standard<'a> {
        Standard {
            text: self,
            opportunities: self.opportunities(corp),
            prior: 0,
            current: 0
        }
    }
}

impl<'a> FullTextHyphenation<Standard<'a>> for &'a str {
    fn fulltext_opportunities(self, corp: &Corpus) -> Vec<usize> {
        let (l_min, r_min) = (corp.left_min, corp.right_min);
        let length_min = l_min + r_min;

        if self.chars().count() < length_min {
            return vec![];
        }

        let by_word = self.split_word_bound_indices();
        by_word.flat_map(|(i, word)| {
            let pts = match corp.exceptions.iter()
                                .filter_map(|exs| exs.score(word))
                                .next() {
                                    Some(vec) => Cow::Borrowed(vec),
                                    None => Cow::Owned(corp.patterns.score(word))
            }.into_owned();

            let hyph_length = pts.len();
            let remaining = if hyph_length >= length_min - 1 {
                hyph_length + 2 - length_min
            } else { 0 };

            word.char_indices().skip(l_min)
                .zip(pts.into_iter().skip(l_min - 1).take(remaining))
                .filter(|&(_, p)| p % 2 != 0)
                .map(move |((i1, _), _)| i + i1)
        }).collect()
    }

    fn fulltext_hyphenate(self, corp: &Corpus) -> Standard<'a> {
        Standard {
            text: self,
            opportunities: self.fulltext_opportunities(corp),
            prior: 0,
            current: 0
        }

    }
}
<|endoftext|>