<commit_before>//! `las` headers describe the point format, data bounds, and other metadata.

use std::io::{Read, Write};
use std::fmt;

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

use Result;
use error::Error;
use io::read_full;

/// This constant value is the bytes in your normal header. There are worlds where people put crap
/// into headers that don't belong there, so we have to guard against this.
const DEFAULT_BYTES_IN_HEADER: u16 = 227;

/// A las header.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Header {
    /// The las file signature.
    ///
    /// Should always be "LASF".
    pub file_signature: [u8; 4],
    /// A numeric identifier for this file.
    pub file_source_id: u16,
    /// Unused in early version, and exapanded to help with GPS time offsets in later versions.
    pub global_encoding: u16,
    /// The first of four parts of the project id.
    pub guid_data_1: u32,
    /// The second of four parts of the project id.
    pub guid_data_2: u16,
    /// The third of four parts of the project id.
    pub guid_data_3: u16,
    /// The fourth of four parts of the project id.
    pub guid_data_4: [u8; 8],
    /// The las major version.
    ///
    /// Should always be 1.
    pub version_major: u8,
    /// The las minor version.
    pub version_minor: u8,
    /// Generally the hardware system that created the las file.
    ///
    /// Can also be the algorithm that produced the lasfile. This field is poorly defined.
    pub system_identifier: [u8; 32],
    /// The software the generated the las file.
    pub generating_software: [u8; 32],
    /// The day of the year, indexed to 1.
    pub file_creation_day_of_year: u16,
    /// The year of file creation.
    pub file_creation_year: u16,
    /// The size of the las header.
    ///
    /// Softwares are technically allowed to add custom extensions to the las header, which would
    /// then affect this header size, but that is discouraged as such support is not universal.
    pub header_size: u16,
    /// The byte offset to the beginning of point data.
    ///
    /// Includes the size of the header and the variable length records.
    pub offset_to_point_data: u32,
    /// The number of variable length records.
    pub number_of_variable_length_records: u32,
    /// The point data format.
    pub point_data_format: PointDataFormat,
    /// The length of one point data record, in bytes.
    pub point_data_record_length: u16,
    /// The total number of point records.
    pub number_of_point_records: u32,
    /// The number of point records of each return number.
    ///
    /// This only supports five returns per pulse.
    pub number_of_points_by_return: [u32; 5],
    /// The x scale factor for each point.
    pub x_scale_factor: f64,
    /// The y scale factor for each point.
    pub y_scale_factor: f64,
    /// The z scale factor for each point.
    pub z_scale_factor: f64,
    /// The x offset for each point.
    pub x_offset: f64,
    /// The y offset for each point.
    pub y_offset: f64,
    /// The z offset for each point.
    pub z_offset: f64,
    /// The maximum x value.
    pub x_max: f64,
    /// The minimum x value.
    pub x_min: f64,
    /// The maximum y value.
    pub y_max: f64,
    /// The minimum y value.
    pub y_min: f64,
    /// The maximum z value.
    pub z_max: f64,
    /// The minimum z value.
    pub z_min: f64,
}

impl Header {
    /// Reads a header from a `Read`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs::File;
    /// use las::header::Header;
    /// let ref mut file = File::open("data/1.0_0.las").unwrap();
    /// let header = Header::read_from(file);
    /// ```
    pub fn read_from<R: Read>(reader: &mut R) -> Result<Header> {
        let mut header = Header::new();
        try!(read_full(reader, &mut header.file_signature));
        header.file_source_id = try!(reader.read_u16::<LittleEndian>());
        header.global_encoding = try!(reader.read_u16::<LittleEndian>());
        header.guid_data_1 = try!(reader.read_u32::<LittleEndian>());
        header.guid_data_2 = try!(reader.read_u16::<LittleEndian>());
        header.guid_data_3 = try!(reader.read_u16::<LittleEndian>());
        try!(read_full(reader, &mut header.guid_data_4));
        header.version_major = try!(reader.read_u8());
        header.version_minor = try!(reader.read_u8());
        try!(read_full(reader, &mut header.system_identifier));
        try!(read_full(reader, &mut header.generating_software));
        header.file_creation_day_of_year = try!(reader.read_u16::<LittleEndian>());
        header.file_creation_year = try!(reader.read_u16::<LittleEndian>());
        header.header_size = try!(reader.read_u16::<LittleEndian>());
        header.offset_to_point_data = try!(reader.read_u32::<LittleEndian>());
        header.number_of_variable_length_records = try!(reader.read_u32::<LittleEndian>());
        header.point_data_format = try!(PointDataFormat::from_u8(try!(reader.read_u8())));
        header.point_data_record_length = try!(reader.read_u16::<LittleEndian>());
        header.number_of_point_records = try!(reader.read_u32::<LittleEndian>());
        for n in &mut header.number_of_points_by_return {
            *n = try!(reader.read_u32::<LittleEndian>());
        }
        header.x_scale_factor = try!(reader.read_f64::<LittleEndian>());
        header.y_scale_factor = try!(reader.read_f64::<LittleEndian>());
        header.z_scale_factor = try!(reader.read_f64::<LittleEndian>());
        header.x_offset = try!(reader.read_f64::<LittleEndian>());
        header.y_offset = try!(reader.read_f64::<LittleEndian>());
        header.z_offset = try!(reader.read_f64::<LittleEndian>());
        header.x_max = try!(reader.read_f64::<LittleEndian>());
        header.x_min = try!(reader.read_f64::<LittleEndian>());
        header.y_max = try!(reader.read_f64::<LittleEndian>());
        header.y_min = try!(reader.read_f64::<LittleEndian>());
        header.z_max = try!(reader.read_f64::<LittleEndian>());
        header.z_min = try!(reader.read_f64::<LittleEndian>());
        Ok(header)
    }

    /// Creates a new, empty header.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::Header;
    /// let header = Header::new();
    /// ```
    pub fn new() -> Header {
        Header {
            file_signature: *b"LASF",
            file_source_id: 0,
            global_encoding: 0,
            guid_data_1: 0,
            guid_data_2: 0,
            guid_data_3: 0,
            guid_data_4: [0; 8],
            version_major: 1,
            version_minor: 0,
            system_identifier: [0; 32],
            generating_software: [0; 32],
            file_creation_day_of_year: 0,
            file_creation_year: 0,
            header_size: 0,
            offset_to_point_data: 0,
            number_of_variable_length_records: 0,
            point_data_format: PointDataFormat(0),
            point_data_record_length: 0,
            number_of_point_records: 0,
            number_of_points_by_return: [0; 5],
            x_scale_factor: 1.0,
            y_scale_factor: 1.0,
            z_scale_factor: 1.0,
            x_offset: 0.0,
            y_offset: 0.0,
            z_offset: 0.0,
            x_max: 0.0,
            x_min: 0.0,
            y_max: 0.0,
            y_min: 0.0,
            z_max: 0.0,
            z_min: 0.0,
        }
    }

    /// Writes this header to a `Write`.
    ///
    /// Returns the number of bytes written.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::io::Cursor;
    /// use las::header::Header;
    /// let header = Header::new();
    /// let ref mut writer = Cursor::new(Vec::new());
    /// let bytes_written = header.write_to(writer).unwrap();
    /// ```
    pub fn write_to<W: Write>(&self, writer: &mut W) -> Result<u16> {
        try!(writer.write_all(&self.file_signature));
        try!(writer.write_u16::<LittleEndian>(self.file_source_id));
        try!(writer.write_u16::<LittleEndian>(self.global_encoding));
        try!(writer.write_u32::<LittleEndian>(self.guid_data_1));
        try!(writer.write_u16::<LittleEndian>(self.guid_data_2));
        try!(writer.write_u16::<LittleEndian>(self.guid_data_3));
        try!(writer.write_all(&self.guid_data_4));
        try!(writer.write_u8(self.version_major));
        try!(writer.write_u8(self.version_minor));
        try!(writer.write_all(&self.system_identifier));
        try!(writer.write_all(&self.generating_software));
        try!(writer.write_u16::<LittleEndian>(self.file_creation_day_of_year));
        try!(writer.write_u16::<LittleEndian>(self.file_creation_year));
        try!(writer.write_u16::<LittleEndian>(self.header_size));
        try!(writer.write_u32::<LittleEndian>(self.offset_to_point_data));
        try!(writer.write_u32::<LittleEndian>(self.number_of_variable_length_records));
        try!(writer.write_u8(self.point_data_format.0));
        try!(writer.write_u16::<LittleEndian>(self.point_data_record_length));
        try!(writer.write_u32::<LittleEndian>(self.number_of_point_records));
        for n in &self.number_of_points_by_return {
            try!(writer.write_u32::<LittleEndian>(*n));
        }
        try!(writer.write_f64::<LittleEndian>(self.x_scale_factor));
        try!(writer.write_f64::<LittleEndian>(self.y_scale_factor));
        try!(writer.write_f64::<LittleEndian>(self.z_scale_factor));
        try!(writer.write_f64::<LittleEndian>(self.x_offset));
        try!(writer.write_f64::<LittleEndian>(self.y_offset));
        try!(writer.write_f64::<LittleEndian>(self.z_offset));
        try!(writer.write_f64::<LittleEndian>(self.x_max));
        try!(writer.write_f64::<LittleEndian>(self.x_min));
        try!(writer.write_f64::<LittleEndian>(self.y_max));
        try!(writer.write_f64::<LittleEndian>(self.y_min));
        try!(writer.write_f64::<LittleEndian>(self.z_max));
        try!(writer.write_f64::<LittleEndian>(self.z_min));
        Ok(DEFAULT_BYTES_IN_HEADER)
    }

    /// Calculates the size of this header and assigns it to the header structure.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::Header;
    /// let mut header = Header::new();
    /// header.calculate_size();
    /// assert_eq!(227, header.header_size);
    /// ```
    pub fn calculate_size(&mut self) {
        self.header_size = DEFAULT_BYTES_IN_HEADER
    }
}

/// A wrapper around the u8 of a point data format.
///
/// Formats have powers, so we encapsulate that through this struct.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct PointDataFormat(u8);

impl PointDataFormat {
    /// Creates a point data format for this u8.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::PointDataFormat;
    /// assert!(PointDataFormat::from_u8(0).is_ok());
    /// assert!(PointDataFormat::from_u8(1).is_ok());
    /// assert!(PointDataFormat::from_u8(127).is_err());
    /// ```
    pub fn from_u8(n: u8) -> Result<PointDataFormat> {
        if n < 4 {
            Ok(PointDataFormat(n))
        } else {
            Err(Error::InvalidPointDataFormat(n))
        }
    }

    /// Returns true if this point data format has time.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::PointDataFormat;
    /// assert!(!PointDataFormat::from_u8(0).unwrap().has_time());
    /// assert!(PointDataFormat::from_u8(1).unwrap().has_time());
    /// ```
    pub fn has_time(&self) -> bool {
        self.0 == 1 || self.0 == 3
    }

    /// Returns true if this point data format has color.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::PointDataFormat;
    /// assert!(!PointDataFormat::from_u8(0).unwrap().has_color());
    /// assert!(PointDataFormat::from_u8(2).unwrap().has_color());
    /// ```
    pub fn has_color(&self) -> bool {
        self.0 == 2 || self.0 == 3
    }
}

impl fmt::Display for PointDataFormat {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}
<commit_msg>Write our information in the generating software<commit_after>//! `las` headers describe the point format, data bounds, and other metadata.

use std::io::{Read, Write};
use std::fmt;
use std::iter::repeat;

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

use Result;
use error::Error;
use io::read_full;

/// This constant value is the bytes in your normal header. There are worlds where people put crap
/// into headers that don't belong there, so we have to guard against this.
const DEFAULT_BYTES_IN_HEADER: u16 = 227;

/// A las header.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Header {
    /// The las file signature.
    ///
    /// Should always be "LASF".
    pub file_signature: [u8; 4],
    /// A numeric identifier for this file.
    pub file_source_id: u16,
    /// Unused in early version, and exapanded to help with GPS time offsets in later versions.
    pub global_encoding: u16,
    /// The first of four parts of the project id.
    pub guid_data_1: u32,
    /// The second of four parts of the project id.
    pub guid_data_2: u16,
    /// The third of four parts of the project id.
    pub guid_data_3: u16,
    /// The fourth of four parts of the project id.
    pub guid_data_4: [u8; 8],
    /// The las major version.
    ///
    /// Should always be 1.
    pub version_major: u8,
    /// The las minor version.
    pub version_minor: u8,
    /// Generally the hardware system that created the las file.
    ///
    /// Can also be the algorithm that produced the lasfile. This field is poorly defined.
    pub system_identifier: [u8; 32],
    /// The software the generated the las file.
    pub generating_software: [u8; 32],
    /// The day of the year, indexed to 1.
    pub file_creation_day_of_year: u16,
    /// The year of file creation.
    pub file_creation_year: u16,
    /// The size of the las header.
    ///
    /// Softwares are technically allowed to add custom extensions to the las header, which would
    /// then affect this header size, but that is discouraged as such support is not universal.
    pub header_size: u16,
    /// The byte offset to the beginning of point data.
    ///
    /// Includes the size of the header and the variable length records.
    pub offset_to_point_data: u32,
    /// The number of variable length records.
    pub number_of_variable_length_records: u32,
    /// The point data format.
    pub point_data_format: PointDataFormat,
    /// The length of one point data record, in bytes.
    pub point_data_record_length: u16,
    /// The total number of point records.
    pub number_of_point_records: u32,
    /// The number of point records of each return number.
    ///
    /// This only supports five returns per pulse.
    pub number_of_points_by_return: [u32; 5],
    /// The x scale factor for each point.
    pub x_scale_factor: f64,
    /// The y scale factor for each point.
    pub y_scale_factor: f64,
    /// The z scale factor for each point.
    pub z_scale_factor: f64,
    /// The x offset for each point.
    pub x_offset: f64,
    /// The y offset for each point.
    pub y_offset: f64,
    /// The z offset for each point.
    pub z_offset: f64,
    /// The maximum x value.
    pub x_max: f64,
    /// The minimum x value.
    pub x_min: f64,
    /// The maximum y value.
    pub y_max: f64,
    /// The minimum y value.
    pub y_min: f64,
    /// The maximum z value.
    pub z_max: f64,
    /// The minimum z value.
    pub z_min: f64,
}

impl Header {
    /// Reads a header from a `Read`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs::File;
    /// use las::header::Header;
    /// let ref mut file = File::open("data/1.0_0.las").unwrap();
    /// let header = Header::read_from(file);
    /// ```
    pub fn read_from<R: Read>(reader: &mut R) -> Result<Header> {
        let mut header = Header::new();
        try!(read_full(reader, &mut header.file_signature));
        header.file_source_id = try!(reader.read_u16::<LittleEndian>());
        header.global_encoding = try!(reader.read_u16::<LittleEndian>());
        header.guid_data_1 = try!(reader.read_u32::<LittleEndian>());
        header.guid_data_2 = try!(reader.read_u16::<LittleEndian>());
        header.guid_data_3 = try!(reader.read_u16::<LittleEndian>());
        try!(read_full(reader, &mut header.guid_data_4));
        header.version_major = try!(reader.read_u8());
        header.version_minor = try!(reader.read_u8());
        try!(read_full(reader, &mut header.system_identifier));
        try!(read_full(reader, &mut header.generating_software));
        header.file_creation_day_of_year = try!(reader.read_u16::<LittleEndian>());
        header.file_creation_year = try!(reader.read_u16::<LittleEndian>());
        header.header_size = try!(reader.read_u16::<LittleEndian>());
        header.offset_to_point_data = try!(reader.read_u32::<LittleEndian>());
        header.number_of_variable_length_records = try!(reader.read_u32::<LittleEndian>());
        header.point_data_format = try!(PointDataFormat::from_u8(try!(reader.read_u8())));
        header.point_data_record_length = try!(reader.read_u16::<LittleEndian>());
        header.number_of_point_records = try!(reader.read_u32::<LittleEndian>());
        for n in &mut header.number_of_points_by_return {
            *n = try!(reader.read_u32::<LittleEndian>());
        }
        header.x_scale_factor = try!(reader.read_f64::<LittleEndian>());
        header.y_scale_factor = try!(reader.read_f64::<LittleEndian>());
        header.z_scale_factor = try!(reader.read_f64::<LittleEndian>());
        header.x_offset = try!(reader.read_f64::<LittleEndian>());
        header.y_offset = try!(reader.read_f64::<LittleEndian>());
        header.z_offset = try!(reader.read_f64::<LittleEndian>());
        header.x_max = try!(reader.read_f64::<LittleEndian>());
        header.x_min = try!(reader.read_f64::<LittleEndian>());
        header.y_max = try!(reader.read_f64::<LittleEndian>());
        header.y_min = try!(reader.read_f64::<LittleEndian>());
        header.z_max = try!(reader.read_f64::<LittleEndian>());
        header.z_min = try!(reader.read_f64::<LittleEndian>());
        Ok(header)
    }

    /// Creates a new, empty header.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::Header;
    /// let header = Header::new();
    /// ```
    pub fn new() -> Header {
        let name_and_version = format!("las-rs {}", env!("CARGO_PKG_VERSION")).into_bytes();
        let mut generating_software = [0; 32];
        for (c, b) in name_and_version.iter()
                                      .chain(repeat(&0).take(generating_software.len() -
                                                             name_and_version.len()))
                                      .zip(generating_software.iter_mut()) {
            *b = *c;
        }
        Header {
            file_signature: *b"LASF",
            file_source_id: 0,
            global_encoding: 0,
            guid_data_1: 0,
            guid_data_2: 0,
            guid_data_3: 0,
            guid_data_4: [0; 8],
            version_major: 1,
            version_minor: 0,
            system_identifier: [0; 32],
            generating_software: generating_software,
            file_creation_day_of_year: 0,
            file_creation_year: 0,
            header_size: 0,
            offset_to_point_data: 0,
            number_of_variable_length_records: 0,
            point_data_format: PointDataFormat(0),
            point_data_record_length: 0,
            number_of_point_records: 0,
            number_of_points_by_return: [0; 5],
            x_scale_factor: 1.0,
            y_scale_factor: 1.0,
            z_scale_factor: 1.0,
            x_offset: 0.0,
            y_offset: 0.0,
            z_offset: 0.0,
            x_max: 0.0,
            x_min: 0.0,
            y_max: 0.0,
            y_min: 0.0,
            z_max: 0.0,
            z_min: 0.0,
        }
    }

    /// Writes this header to a `Write`.
    ///
    /// Returns the number of bytes written.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::io::Cursor;
    /// use las::header::Header;
    /// let header = Header::new();
    /// let ref mut writer = Cursor::new(Vec::new());
    /// let bytes_written = header.write_to(writer).unwrap();
    /// ```
    pub fn write_to<W: Write>(&self, writer: &mut W) -> Result<u16> {
        try!(writer.write_all(&self.file_signature));
        try!(writer.write_u16::<LittleEndian>(self.file_source_id));
        try!(writer.write_u16::<LittleEndian>(self.global_encoding));
        try!(writer.write_u32::<LittleEndian>(self.guid_data_1));
        try!(writer.write_u16::<LittleEndian>(self.guid_data_2));
        try!(writer.write_u16::<LittleEndian>(self.guid_data_3));
        try!(writer.write_all(&self.guid_data_4));
        try!(writer.write_u8(self.version_major));
        try!(writer.write_u8(self.version_minor));
        try!(writer.write_all(&self.system_identifier));
        try!(writer.write_all(&self.generating_software));
        try!(writer.write_u16::<LittleEndian>(self.file_creation_day_of_year));
        try!(writer.write_u16::<LittleEndian>(self.file_creation_year));
        try!(writer.write_u16::<LittleEndian>(self.header_size));
        try!(writer.write_u32::<LittleEndian>(self.offset_to_point_data));
        try!(writer.write_u32::<LittleEndian>(self.number_of_variable_length_records));
        try!(writer.write_u8(self.point_data_format.0));
        try!(writer.write_u16::<LittleEndian>(self.point_data_record_length));
        try!(writer.write_u32::<LittleEndian>(self.number_of_point_records));
        for n in &self.number_of_points_by_return {
            try!(writer.write_u32::<LittleEndian>(*n));
        }
        try!(writer.write_f64::<LittleEndian>(self.x_scale_factor));
        try!(writer.write_f64::<LittleEndian>(self.y_scale_factor));
        try!(writer.write_f64::<LittleEndian>(self.z_scale_factor));
        try!(writer.write_f64::<LittleEndian>(self.x_offset));
        try!(writer.write_f64::<LittleEndian>(self.y_offset));
        try!(writer.write_f64::<LittleEndian>(self.z_offset));
        try!(writer.write_f64::<LittleEndian>(self.x_max));
        try!(writer.write_f64::<LittleEndian>(self.x_min));
        try!(writer.write_f64::<LittleEndian>(self.y_max));
        try!(writer.write_f64::<LittleEndian>(self.y_min));
        try!(writer.write_f64::<LittleEndian>(self.z_max));
        try!(writer.write_f64::<LittleEndian>(self.z_min));
        Ok(DEFAULT_BYTES_IN_HEADER)
    }

    /// Calculates the size of this header and assigns it to the header structure.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::Header;
    /// let mut header = Header::new();
    /// header.calculate_size();
    /// assert_eq!(227, header.header_size);
    /// ```
    pub fn calculate_size(&mut self) {
        self.header_size = DEFAULT_BYTES_IN_HEADER
    }
}

/// A wrapper around the u8 of a point data format.
///
/// Formats have powers, so we encapsulate that through this struct.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct PointDataFormat(u8);

impl PointDataFormat {
    /// Creates a point data format for this u8.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::PointDataFormat;
    /// assert!(PointDataFormat::from_u8(0).is_ok());
    /// assert!(PointDataFormat::from_u8(1).is_ok());
    /// assert!(PointDataFormat::from_u8(127).is_err());
    /// ```
    pub fn from_u8(n: u8) -> Result<PointDataFormat> {
        if n < 4 {
            Ok(PointDataFormat(n))
        } else {
            Err(Error::InvalidPointDataFormat(n))
        }
    }

    /// Returns true if this point data format has time.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::PointDataFormat;
    /// assert!(!PointDataFormat::from_u8(0).unwrap().has_time());
    /// assert!(PointDataFormat::from_u8(1).unwrap().has_time());
    /// ```
    pub fn has_time(&self) -> bool {
        self.0 == 1 || self.0 == 3
    }

    /// Returns true if this point data format has color.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::PointDataFormat;
    /// assert!(!PointDataFormat::from_u8(0).unwrap().has_color());
    /// assert!(PointDataFormat::from_u8(2).unwrap().has_color());
    /// ```
    pub fn has_color(&self) -> bool {
        self.0 == 2 || self.0 == 3
    }
}

impl fmt::Display for PointDataFormat {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Pierre Marijon.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! GFF3 format reading and writing.
//!
//! GFF2 definition : http://gmod.org/wiki/GFF2#The_GFF2_File_Format (not yet support)
//! GTF2 definition : http://mblab.wustl.edu/GTF2.html (not yet support)
//! GFF3 definition : http://gmod.org/wiki/GFF3#GFF3_Format
//!
//! # Example
//!
//! ```
//! use std::io;
//! use bio::io::gff;
//! let reader = gff::Reader::new(io::stdin());
//! ```

use std::io;
use std::fs;
use std::path::Path;
use std::convert::AsRef;
use std::collections::HashMap;

use csv;

use io::Strand;

/// A GFF reader.
pub struct Reader<R: io::Read> {
    inner: csv::Reader<R>,
}

impl Reader<fs::File> {
    /// Read GFF from given file path.
    pub fn from_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
        fs::File::open(path).map(Reader::new)
    }
}

impl<R: io::Read> Reader<R> {
    /// Create a new GFF reader given an instance of `io::Read`.
    pub fn new(reader: R) -> Self {
        Reader {
            inner: csv::Reader::from_reader(reader).delimiter(b'\t').has_headers(false)
        }
    }

    /// Iterate over all records.
    pub fn records(&mut self) -> Records<R> {
        Records { inner: self.inner.decode() }
    }
}

/// A GFF record.
pub struct Records<'a, R: 'a + io::Read> {
    inner: csv::DecodedRecords<'a, R, (String, String, String, u64, u64, String, String, String, String)>,
}

impl<'a, R: io::Read> Iterator for Records<'a, R> {
    type Item = csv::Result<Record>;

    fn next(&mut self) -> Option<csv::Result<Record>> {
        self.inner.next().map(|res| {
            res.map(|(seqname, source, feature_type, start, end, score, strand, frame, attributes)| {
                Record {
                    seqname: seqname,
                    source: source,
                    feature_type: feature_type,
                    start: start,
                    end: end,
                    score: score,
                    strand: strand,
                    frame: frame,
                    attributes: csv::Reader::from_string(attributes)
                        .delimiter(b'=')
                        .record_terminator(csv::RecordTerminator::Any(b';'))
                        .has_headers(false)
                        .decode().collect::<csv::Result<HashMap<String, String>>>().unwrap(),
                }
            })
        })
    }
}

/// A GFF writer.
pub struct Writer<W: io::Write> {
    inner: csv::Writer<W>,
}

impl Writer<fs::File> {
    /// Write to a given file path.
    pub fn to_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
        fs::File::create(path).map(Writer::new)
    }
}

impl<W: io::Write> Writer<W> {
    /// Write to a given writer.
    pub fn new(writer: W) -> Self {
        Writer { inner: csv::Writer::from_writer(writer).delimiter(b'\t').flexible(true) }
    }

    /// Write a given GFF record.
    pub fn write(&mut self, record: Record) -> csv::Result<()> {
        if !record.attributes.is_empty() {
            self.inner.encode((
                record.seqname,
                record.source,
                record.feature_type,
                record.start,
                record.end,
                record.score,
                record.strand,
                record.frame,
                record.attributes.iter().map(|(a, b)| format!("{}={}", a, b)).collect::<Vec<_>>().join(";"),
                ))

        } else {
            self.inner.encode((record.seqname, record.source, record.feature_type, record.start, record.end, record.score, record.strand, record.frame, ""))
        }
    }
}

/// A GFF record
#[derive(RustcEncodable)]
pub struct Record {
    seqname: String,
    source: String,
    feature_type: String,
    start: u64,
    end: u64,
    score: String,
    strand: String,
    frame: String,
    attributes: HashMap<String, String>,
}

impl Record {
    /// Create a new GFF record.
    pub fn new() -> Self {
        Record {
            seqname: "".to_owned(),
            source: "".to_owned(),
            feature_type: "".to_owned(),
            start: 0,
            end: 0,
            score: ".".to_owned(),
            strand: ".".to_owned(),
            frame: "".to_owned(),
            attributes: HashMap::<String, String>::new(),
        }
    }

    /// Sequence name of the feature.
    pub fn seqname(&self) -> &str {
        &self.seqname
    }

    /// Source of the feature.
    pub fn source(&self) -> &str {
        &self.source
    }

    /// Type of the feature.
    pub fn feature_type(&self) -> &str {
        &self.feature_type
    }

    /// Start position of feature (1-based).
    pub fn start(&self) -> u64 {
        self.start
    }

    /// End position of feature (1-based, not included).
    pub fn end(&self) -> u64 {
        self.end
    }

    /// Score of feature
    pub fn score(&self) -> Option<u64> {
        match self.score.as_ref() {
            "." => None,
            _ => self.score.parse::<u64>().ok(),
        }
    }

    /// Strand of the feature.
    pub fn strand(&self) -> Option<Strand> {
        match self.strand.as_ref() {
            "+" => Some(Strand::Forward),
            "-" => Some(Strand::Reverse),
            _ => None,
        }
    }

    /// Frame of the feature.
    pub fn frame(&self) -> &str {
        &self.frame
    }

    /// Attribute of feature
    pub fn attributes(&self) -> &HashMap<String, String> {
        &self.attributes
    }

    /// Set seqname of feature.
    pub fn set_seqname(&mut self, seqname: &str) {
        self.seqname = seqname.to_owned();
    }

    /// Set source of feature.
    pub fn set_source(&mut self, source: &str) {
        self.source = source.to_owned();
    }

    /// Set type of feature.
    pub fn set_feature_type(&mut self, feature_type: &str) {
        self.feature_type = feature_type.to_owned();
    }

    /// Set start of feature.
    pub fn set_start(&mut self, start: u64) {
        self.start = start;
    }

    /// Set end of feature.
    pub fn set_end(&mut self, end: u64) {
        self.end = end;
    }

    /// Set score of feature.
    pub fn set_score(&mut self, score: &str) {
        self.score = score.to_owned();
    }

    /// Set strand of feature.
    pub fn set_strand(&mut self, strand: &str) {
        self.strand = strand.to_owned();
    }

    // pub fn set_attributes(&mut self, attributes: &HashMap<String, String>) {
    //     self.attributes = attributes;
    // }
}

#[cfg(test)]
mod tests {
    use super::*;
    use io::Strand;
    use std::collections::HashMap;

    const GFF_FILE: &'static [u8] = b"P0A7B8\tUniProtKB\tInitiator methionine\t1\t1\t.\t.\t.\tNote=Removed;ID=test
P0A7B8\tUniProtKB\tChain\t2\t176\t50\t+\t.\tNote=ATP-dependent protease subunit HslV;ID=PRO_0000148105
";
    //required because HashMap iter on element randomly
    const GFF_FILE_NO_ATTRIB: &'static [u8] = b"P0A7B8\tUniProtKB\tInitiator methionine\t1\t1\t.\t.\t.\t
P0A7B8\tUniProtKB\tChain\t2\t176\t50\t+\t.\t
";

    #[test]
    fn test_reader() {
        let seqname = ["P0A7B8", "P0A7B8"];
        let source = ["UniProtKB", "UniProtKB"];
        let feature_type = ["Initiator methionine", "Chain"];
        let starts = [1, 2];
        let ends = [1, 176];
        let scores = [None, Some(50)];
        let strand = [None, Some(Strand::Forward)];
        let frame = [".", "."];
        let mut attributes = [HashMap::new(), HashMap::new()];
        attributes[0].insert("ID".to_owned(), "test".to_owned());
        attributes[0].insert("Note".to_owned(), "Removed".to_owned());
        attributes[1].insert("ID".to_owned(), "PRO_0000148105".to_owned());
        attributes[1].insert("Note".to_owned(), "ATP-dependent protease subunit HslV".to_owned());

        let mut reader = Reader::new(GFF_FILE);
        for (i, r) in reader.records().enumerate() {
            let record = r.ok().expect("Error reading record");
            assert_eq!(record.seqname(), seqname[i]);
            assert_eq!(record.source(), source[i]);
            assert_eq!(record.feature_type(), feature_type[i]);
            assert_eq!(record.start(), starts[i]);
            assert_eq!(record.end(), ends[i]);
            assert_eq!(record.score(), scores[i]);
            assert_eq!(record.strand(), strand[i]);
            assert_eq!(record.frame(), frame[i]);
            assert_eq!(record.attributes, attributes[i]);
        }
    }

    #[test]
    fn test_writer() {
        let mut reader = Reader::new(GFF_FILE_NO_ATTRIB);
        let mut writer = Writer::new(vec![]);
        for r in reader.records() {
            writer.write(r.ok().expect("Error reading record")).ok().expect("Error writing record");
        }
        assert_eq!(writer.inner.as_string(), String::from_utf8_lossy(GFF_FILE_NO_ATTRIB))
    }
}
<commit_msg>typo mistake<commit_after>// Copyright 2016 Pierre Marijon.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! GFF3 format reading and writing.
//!
//! GFF2 definition : http://gmod.org/wiki/GFF2#The_GFF2_File_Format (not yet support)
//! GTF2 definition : http://mblab.wustl.edu/GTF2.html (not yet support)
//! GFF3 definition : http://gmod.org/wiki/GFF3#GFF3_Format
//!
//! # Example
//!
//! ```
//! use std::io;
//! use bio::io::gff;
//! let reader = gff::Reader::new(io::stdin());
//! ```

use std::io;
use std::fs;
use std::path::Path;
use std::convert::AsRef;
use std::collections::HashMap;

use csv;

use io::Strand;

/// A GFF reader.
pub struct Reader<R: io::Read> {
    inner: csv::Reader<R>,
}

impl Reader<fs::File> {
    /// Read GFF from given file path.
    pub fn from_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
        fs::File::open(path).map(Reader::new)
    }
}

impl<R: io::Read> Reader<R> {
    /// Create a new GFF reader given an instance of `io::Read`.
    pub fn new(reader: R) -> Self {
        Reader {
            inner: csv::Reader::from_reader(reader).delimiter(b'\t').has_headers(false)
        }
    }

    /// Iterate over all records.
    pub fn records(&mut self) -> Records<R> {
        Records { inner: self.inner.decode() }
    }
}

/// A GFF record.
pub struct Records<'a, R: 'a + io::Read> {
    inner: csv::DecodedRecords<'a, R, (String, String, String, u64, u64, String, String, String, String)>,
}

impl<'a, R: io::Read> Iterator for Records<'a, R> {
    type Item = csv::Result<Record>;

    fn next(&mut self) -> Option<csv::Result<Record>> {
        self.inner.next().map(|res| {
            res.map(|(seqname, source, feature_type, start, end, score, strand, frame, attributes)| {
                Record {
                    seqname: seqname,
                    source: source,
                    feature_type: feature_type,
                    start: start,
                    end: end,
                    score: score,
                    strand: strand,
                    frame: frame,
                    attributes: csv::Reader::from_string(attributes)
                        .delimiter(b'=')
                        .record_terminator(csv::RecordTerminator::Any(b';'))
                        .has_headers(false)
                        .decode().collect::<csv::Result<HashMap<String, String>>>().unwrap(),
                }
            })
        })
    }
}

/// A GFF writer.
pub struct Writer<W: io::Write> {
    inner: csv::Writer<W>,
}

impl Writer<fs::File> {
    /// Write to a given file path.
    pub fn to_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
        fs::File::create(path).map(Writer::new)
    }
}

impl<W: io::Write> Writer<W> {
    /// Write to a given writer.
    pub fn new(writer: W) -> Self {
        Writer { inner: csv::Writer::from_writer(writer).delimiter(b'\t').flexible(true) }
    }

    /// Write a given GFF record.
    pub fn write(&mut self, record: Record) -> csv::Result<()> {
        if !record.attributes.is_empty() {
            self.inner.encode((
                record.seqname,
                record.source,
                record.feature_type,
                record.start,
                record.end,
                record.score,
                record.strand,
                record.frame,
                record.attributes.iter().map(|(a, b)| format!("{}={}", a, b)).collect::<Vec<_>>().join(";"),
                ))

        } else {
            self.inner.encode((record.seqname, record.source, record.feature_type, record.start, record.end, record.score, record.strand, record.frame, ""))
        }
    }
}

/// A GFF record
#[derive(RustcEncodable)]
pub struct Record {
    seqname: String,
    source: String,
    feature_type: String,
    start: u64,
    end: u64,
    score: String,
    strand: String,
    frame: String,
    attributes: HashMap<String, String>,
}

impl Record {
    /// Create a new GFF record.
    pub fn new() -> Self {
        Record {
            seqname: "".to_owned(),
            source: "".to_owned(),
            feature_type: "".to_owned(),
            start: 0,
            end: 0,
            score: ".".to_owned(),
            strand: ".".to_owned(),
            frame: "".to_owned(),
            attributes: HashMap::<String, String>::new(),
        }
    }

    /// Sequence name of the feature.
    pub fn seqname(&self) -> &str {
        &self.seqname
    }

    /// Source of the feature.
    pub fn source(&self) -> &str {
        &self.source
    }

    /// Type of the feature.
    pub fn feature_type(&self) -> &str {
        &self.feature_type
    }

    /// Start position of feature (1-based).
    pub fn start(&self) -> u64 {
        self.start
    }

    /// End position of feature (1-based, not included).
    pub fn end(&self) -> u64 {
        self.end
    }

    /// Score of feature
    pub fn score(&self) -> Option<u64> {
        match self.score.as_ref() {
            "." => None,
            _ => self.score.parse::<u64>().ok(),
        }
    }

    /// Strand of the feature.
    pub fn strand(&self) -> Option<Strand> {
        match self.strand.as_ref() {
            "+" => Some(Strand::Forward),
            "-" => Some(Strand::Reverse),
            _ => None,
        }
    }

    /// Frame of the feature.
    pub fn frame(&self) -> &str {
        &self.frame
    }

    /// Attribute of feature
    pub fn attributes(&self) -> &HashMap<String, String> {
        &self.attributes
    }

    /// Set seqname of feature.
    pub fn set_seqname(&mut self, seqname: &str) {
        self.seqname = seqname.to_owned();
    }

    /// Set source of feature.
    pub fn set_source(&mut self, source: &str) {
        self.source = source.to_owned();
    }

    /// Set type of feature.
    pub fn set_feature_type(&mut self, feature_type: &str) {
        self.feature_type = feature_type.to_owned();
    }

    /// Set start of feature.
    pub fn set_start(&mut self, start: u64) {
        self.start = start;
    }

    /// Set end of feature.
    pub fn set_end(&mut self, end: u64) {
        self.end = end;
    }

    /// Set score of feature.
    pub fn set_score(&mut self, score: &str) {
        self.score = score.to_owned();
    }

    /// Set strand of feature.
    pub fn set_strand(&mut self, strand: &str) {
        self.strand = strand.to_owned();
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use io::Strand;
    use std::collections::HashMap;

    const GFF_FILE: &'static [u8] = b"P0A7B8\tUniProtKB\tInitiator methionine\t1\t1\t.\t.\t.\tNote=Removed;ID=test
P0A7B8\tUniProtKB\tChain\t2\t176\t50\t+\t.\tNote=ATP-dependent protease subunit HslV;ID=PRO_0000148105
";
    //required because HashMap iter on element randomly
    const GFF_FILE_NO_ATTRIB: &'static [u8] = b"P0A7B8\tUniProtKB\tInitiator methionine\t1\t1\t.\t.\t.\t
P0A7B8\tUniProtKB\tChain\t2\t176\t50\t+\t.\t
";

    #[test]
    fn test_reader() {
        let seqname = ["P0A7B8", "P0A7B8"];
        let source = ["UniProtKB", "UniProtKB"];
        let feature_type = ["Initiator methionine", "Chain"];
        let starts = [1, 2];
        let ends = [1, 176];
        let scores = [None, Some(50)];
        let strand = [None, Some(Strand::Forward)];
        let frame = [".", "."];
        let mut attributes = [HashMap::new(), HashMap::new()];
        attributes[0].insert("ID".to_owned(), "test".to_owned());
        attributes[0].insert("Note".to_owned(), "Removed".to_owned());
        attributes[1].insert("ID".to_owned(), "PRO_0000148105".to_owned());
        attributes[1].insert("Note".to_owned(), "ATP-dependent protease subunit HslV".to_owned());

        let mut reader = Reader::new(GFF_FILE);
        for (i, r) in reader.records().enumerate() {
            let record = r.ok().expect("Error reading record");
            assert_eq!(record.seqname(), seqname[i]);
            assert_eq!(record.source(), source[i]);
            assert_eq!(record.feature_type(), feature_type[i]);
            assert_eq!(record.start(), starts[i]);
            assert_eq!(record.end(), ends[i]);
            assert_eq!(record.score(), scores[i]);
            assert_eq!(record.strand(), strand[i]);
            assert_eq!(record.frame(), frame[i]);
            assert_eq!(record.attributes(), &attributes[i]);
        }
    }

    #[test]
    fn test_writer() {
        let mut reader = Reader::new(GFF_FILE_NO_ATTRIB);
        let mut writer = Writer::new(vec![]);
        for r in reader.records() {
            writer.write(r.ok().expect("Error reading record")).ok().expect("Error writing record");
        }
        assert_eq!(writer.inner.as_string(), String::from_utf8_lossy(GFF_FILE_NO_ATTRIB))
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 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.

//! Traits for conversions between types.
//!
//! The traits in this module provide a general way to talk about conversions
//! from one type to another. They follow the standard Rust conventions of
//! `as`/`into`/`from`.
//!
//! Like many traits, these are often used as bounds for generic functions, to
//! support arguments of multiple types.
//!
//! - Impl the `As*` traits for reference-to-reference conversions
//! - Impl the `Into` trait when you want to consume the value in the conversion
//! - The `From` trait is the most flexible, useful for value _and_ reference conversions
//! - The `TryFrom` and `TryInto` traits behave like `From` and `Into`, but allow for the
//!   conversion to fail
//!
//! As a library author, you should prefer implementing `From<T>` or `TryFrom<T>` rather than
//! `Into<U>` or `TryInto<U>`, as `From` and `TryFrom` provide greater flexibility and offer
//! equivalent `Into` or `TryInto` implementations for free, thanks to a blanket implementation
//! in the standard library.
//!
//! # Generic impl
//!
//! - `AsRef` and `AsMut` auto-dereference if the inner type is a reference
//! - `From<U> for T` implies `Into<T> for U`
//! - `TryFrom<U> for T` implies `TryInto<T> for U`
//! - `From` and `Into` are reflexive, which means that all types can `into()`
//!   themselves and `from()` themselves
//!
//! See each trait for usage examples.

#![stable(feature = "rust1", since = "1.0.0")]

/// A cheap, reference-to-reference conversion.
///
/// `AsRef` is very similar to, but different than, `Borrow`. See
/// [the book][book] for more.
///
/// [book]: ../../book/borrow-and-asref.html
///
/// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which
/// returns an `Option<T>` or a `Result<T, E>`.
///
/// # Examples
///
/// Both `String` and `&str` implement `AsRef<str>`:
///
/// ```
/// fn is_hello<T: AsRef<str>>(s: T) {
///    assert_eq!("hello", s.as_ref());
/// }
///
/// let s = "hello";
/// is_hello(s);
///
/// let s = "hello".to_string();
/// is_hello(s);
/// ```
///
/// # Generic Impls
///
/// - `AsRef` auto-dereferences if the inner type is a reference or a mutable
/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type `&mut Foo` or `&&mut Foo`)
///
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRef<T: ?Sized> {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_ref(&self) -> &T;
}

/// A cheap, mutable reference-to-mutable reference conversion.
///
/// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which
/// returns an `Option<T>` or a `Result<T, E>`.
///
/// # Generic Impls
///
/// - `AsMut` auto-dereferences if the inner type is a reference or a mutable
/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type `&mut Foo` or `&&mut Foo`)
///
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsMut<T: ?Sized> {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_mut(&mut self) -> &mut T;
}

/// A conversion that consumes `self`, which may or may not be expensive.
///
/// **Note: this trait must not fail**. If the conversion can fail, use `TryInto` or a dedicated
/// method which returns an `Option<T>` or a `Result<T, E>`.
///
/// Library authors should not directly implement this trait, but should prefer implementing
/// the `From` trait, which offers greater flexibility and provides an equivalent `Into`
/// implementation for free, thanks to a blanket implementation in the standard library.
///
/// # Examples
///
/// `String` implements `Into<Vec<u8>>`:
///
/// ```
/// fn is_hello<T: Into<Vec<u8>>>(s: T) {
///    let bytes = b"hello".to_vec();
///    assert_eq!(bytes, s.into());
/// }
///
/// let s = "hello".to_string();
/// is_hello(s);
/// ```
///
/// # Generic Impls
///
/// - `From<T> for U` implies `Into<U> for T`
/// - `into()` is reflexive, which means that `Into<T> for T` is implemented
///
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Into<T>: Sized {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn into(self) -> T;
}

/// Construct `Self` via a conversion.
///
/// **Note: this trait must not fail**. If the conversion can fail, use `TryFrom` or a dedicated
/// method which returns an `Option<T>` or a `Result<T, E>`.
///
/// # Examples
///
/// `String` implements `From<&str>`:
///
/// ```
/// let string = "hello".to_string();
/// let other_string = String::from("hello");
///
/// assert_eq!(string, other_string);
/// ```
/// # Generic impls
///
/// - `From<T> for U` implies `Into<U> for T`
/// - `from()` is reflexive, which means that `From<T> for T` is implemented
///
#[stable(feature = "rust1", since = "1.0.0")]
pub trait From<T>: Sized {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn from(T) -> Self;
}

/// An attempted conversion that consumes `self`, which may or may not be expensive.
///
/// Library authors should not directly implement this trait, but should prefer implementing
/// the `TryFrom` trait, which offers greater flexibility and provides an equivalent `TryInto`
/// implementation for free, thanks to a blanket implementation in the standard library.
#[unstable(feature = "try_from", issue = "33417")]
pub trait TryInto<T>: Sized {
    /// The type returned in the event of a conversion error.
    type Err;

    /// Performs the conversion.
    fn try_into(self) -> Result<T, Self::Err>;
}

/// Attempt to construct `Self` via a conversion.
#[unstable(feature = "try_from", issue = "33417")]
pub trait TryFrom<T>: Sized {
    /// The type returned in the event of a conversion error.
    type Err;

    /// Performs the conversion.
    fn try_from(T) -> Result<Self, Self::Err>;
}

////////////////////////////////////////////////////////////////////////////////
// GENERIC IMPLS
////////////////////////////////////////////////////////////////////////////////

// As lifts over &
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a T where T: AsRef<U> {
    fn as_ref(&self) -> &U {
        <T as AsRef<U>>::as_ref(*self)
    }
}

// As lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U> {
    fn as_ref(&self) -> &U {
        <T as AsRef<U>>::as_ref(*self)
    }
}

// FIXME (#23442): replace the above impls for &/&mut with the following more general one:
// // As lifts over Deref
// impl<D: ?Sized + Deref, U: ?Sized> AsRef<U> for D where D::Target: AsRef<U> {
//     fn as_ref(&self) -> &U {
//         self.deref().as_ref()
//     }
// }

// AsMut lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U> {
    fn as_mut(&mut self) -> &mut U {
        (*self).as_mut()
    }
}

// FIXME (#23442): replace the above impl for &mut with the following more general one:
// // AsMut lifts over DerefMut
// impl<D: ?Sized + Deref, U: ?Sized> AsMut<U> for D where D::Target: AsMut<U> {
//     fn as_mut(&mut self) -> &mut U {
//         self.deref_mut().as_mut()
//     }
// }

// From implies Into
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U> Into<U> for T where U: From<T> {
    fn into(self) -> U {
        U::from(self)
    }
}

// From (and thus Into) is reflexive
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> From<T> for T {
    fn from(t: T) -> T { t }
}

// TryFrom implies TryInto
#[unstable(feature = "try_from", issue = "33417")]
impl<T, U> TryInto<U> for T where U: TryFrom<T> {
    type Err = U::Err;

    fn try_into(self) -> Result<U, U::Err> {
        U::try_from(self)
    }
}

////////////////////////////////////////////////////////////////////////////////
// CONCRETE IMPLS
////////////////////////////////////////////////////////////////////////////////

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsRef<[T]> for [T] {
    fn as_ref(&self) -> &[T] {
        self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsMut<[T]> for [T] {
    fn as_mut(&mut self) -> &mut [T] {
        self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<str> for str {
    #[inline]
    fn as_ref(&self) -> &str {
        self
    }
}
<commit_msg>Add missing urls into convert module<commit_after>// Copyright 2014 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.

//! Traits for conversions between types.
//!
//! The traits in this module provide a general way to talk about conversions
//! from one type to another. They follow the standard Rust conventions of
//! `as`/`into`/`from`.
//!
//! Like many traits, these are often used as bounds for generic functions, to
//! support arguments of multiple types.
//!
//! - Impl the `As*` traits for reference-to-reference conversions
//! - Impl the `Into` trait when you want to consume the value in the conversion
//! - The `From` trait is the most flexible, useful for value _and_ reference conversions
//! - The `TryFrom` and `TryInto` traits behave like `From` and `Into`, but allow for the
//!   conversion to fail
//!
//! As a library author, you should prefer implementing `From<T>` or `TryFrom<T>` rather than
//! `Into<U>` or `TryInto<U>`, as `From` and `TryFrom` provide greater flexibility and offer
//! equivalent `Into` or `TryInto` implementations for free, thanks to a blanket implementation
//! in the standard library.
//!
//! # Generic impl
//!
//! - `AsRef` and `AsMut` auto-dereference if the inner type is a reference
//! - `From<U> for T` implies `Into<T> for U`
//! - `TryFrom<U> for T` implies `TryInto<T> for U`
//! - `From` and `Into` are reflexive, which means that all types can `into()`
//!   themselves and `from()` themselves
//!
//! See each trait for usage examples.

#![stable(feature = "rust1", since = "1.0.0")]

/// A cheap, reference-to-reference conversion.
///
/// `AsRef` is very similar to, but different than, [`Borrow`]. See
/// [the book][book] for more.
///
/// [book]: ../../book/borrow-and-asref.html
/// [`Borrow`]: ../../std/borrow/trait.Borrow.html
///
/// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which
/// returns an [`Option<T>`] or a [`Result<T, E>`].
///
/// [`Option<T>`]: ../../std/option/enum.Option.html
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
///
/// # Examples
///
/// Both [`String`] and `&str` implement `AsRef<str>`:
///
/// [`String`]: ../../std/string/struct.String.html
///
/// ```
/// fn is_hello<T: AsRef<str>>(s: T) {
///    assert_eq!("hello", s.as_ref());
/// }
///
/// let s = "hello";
/// is_hello(s);
///
/// let s = "hello".to_string();
/// is_hello(s);
/// ```
///
/// # Generic Impls
///
/// - `AsRef` auto-dereferences if the inner type is a reference or a mutable
/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type `&mut Foo` or `&&mut Foo`)
///
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRef<T: ?Sized> {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_ref(&self) -> &T;
}

/// A cheap, mutable reference-to-mutable reference conversion.
///
/// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which
/// returns an [`Option<T>`] or a [`Result<T, E>`].
///
/// [`Option<T>`]: ../../std/option/enum.Option.html
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
///
/// # Generic Impls
///
/// - `AsMut` auto-dereferences if the inner type is a reference or a mutable
/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type `&mut Foo` or `&&mut Foo`)
///
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsMut<T: ?Sized> {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_mut(&mut self) -> &mut T;
}

/// A conversion that consumes `self`, which may or may not be expensive.
///
/// **Note: this trait must not fail**. If the conversion can fail, use [`TryInto`] or a dedicated
/// method which returns an [`Option<T>`] or a [`Result<T, E>`].
///
/// Library authors should not directly implement this trait, but should prefer implementing
/// the [`From`][From] trait, which offers greater flexibility and provides an equivalent `Into`
/// implementation for free, thanks to a blanket implementation in the standard library.
///
/// # Examples
///
/// [`String`] implements `Into<Vec<u8>>`:
///
/// ```
/// fn is_hello<T: Into<Vec<u8>>>(s: T) {
///    let bytes = b"hello".to_vec();
///    assert_eq!(bytes, s.into());
/// }
///
/// let s = "hello".to_string();
/// is_hello(s);
/// ```
///
/// # Generic Impls
///
/// - `[From<T>][From] for U` implies `Into<U> for T`
/// - [`into()`] is reflexive, which means that `Into<T> for T` is implemented
///
/// [`TryInto`]: trait.TryInto.html
/// [`Option<T>`]: ../../std/option/enum.Option.html
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
/// [`String`]: ../../std/string/struct.String.html
/// [From]: trait.From.html
/// [`into()`]: trait.Into.html#tymethod.into
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Into<T>: Sized {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn into(self) -> T;
}

/// Construct `Self` via a conversion.
///
/// **Note: this trait must not fail**. If the conversion can fail, use [`TryFrom`] or a dedicated
/// method which returns an [`Option<T>`] or a [`Result<T, E>`].
///
/// # Examples
///
/// [`String`] implements `From<&str>`:
///
/// ```
/// let string = "hello".to_string();
/// let other_string = String::from("hello");
///
/// assert_eq!(string, other_string);
/// ```
/// # Generic impls
///
/// - `From<T> for U` implies `[Into<U>] for T`
/// - [`from()`] is reflexive, which means that `From<T> for T` is implemented
///
/// [`TryFrom`]: trait.TryFrom.html
/// [`Option<T>`]: ../../std/option/enum.Option.html
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
/// [`String`]: ../../std/string/struct.String.html
/// [Into<U>]: trait.Into.html
/// [`from()`]: trait.From.html#tymethod.from
#[stable(feature = "rust1", since = "1.0.0")]
pub trait From<T>: Sized {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn from(T) -> Self;
}

/// An attempted conversion that consumes `self`, which may or may not be expensive.
///
/// Library authors should not directly implement this trait, but should prefer implementing
/// the [`TryFrom`] trait, which offers greater flexibility and provides an equivalent `TryInto`
/// implementation for free, thanks to a blanket implementation in the standard library.
///
/// [`TryFrom`]: trait.TryFrom.html
#[unstable(feature = "try_from", issue = "33417")]
pub trait TryInto<T>: Sized {
    /// The type returned in the event of a conversion error.
    type Err;

    /// Performs the conversion.
    fn try_into(self) -> Result<T, Self::Err>;
}

/// Attempt to construct `Self` via a conversion.
#[unstable(feature = "try_from", issue = "33417")]
pub trait TryFrom<T>: Sized {
    /// The type returned in the event of a conversion error.
    type Err;

    /// Performs the conversion.
    fn try_from(T) -> Result<Self, Self::Err>;
}

////////////////////////////////////////////////////////////////////////////////
// GENERIC IMPLS
////////////////////////////////////////////////////////////////////////////////

// As lifts over &
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a T where T: AsRef<U> {
    fn as_ref(&self) -> &U {
        <T as AsRef<U>>::as_ref(*self)
    }
}

// As lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U> {
    fn as_ref(&self) -> &U {
        <T as AsRef<U>>::as_ref(*self)
    }
}

// FIXME (#23442): replace the above impls for &/&mut with the following more general one:
// // As lifts over Deref
// impl<D: ?Sized + Deref, U: ?Sized> AsRef<U> for D where D::Target: AsRef<U> {
//     fn as_ref(&self) -> &U {
//         self.deref().as_ref()
//     }
// }

// AsMut lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U> {
    fn as_mut(&mut self) -> &mut U {
        (*self).as_mut()
    }
}

// FIXME (#23442): replace the above impl for &mut with the following more general one:
// // AsMut lifts over DerefMut
// impl<D: ?Sized + Deref, U: ?Sized> AsMut<U> for D where D::Target: AsMut<U> {
//     fn as_mut(&mut self) -> &mut U {
//         self.deref_mut().as_mut()
//     }
// }

// From implies Into
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U> Into<U> for T where U: From<T> {
    fn into(self) -> U {
        U::from(self)
    }
}

// From (and thus Into) is reflexive
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> From<T> for T {
    fn from(t: T) -> T { t }
}

// TryFrom implies TryInto
#[unstable(feature = "try_from", issue = "33417")]
impl<T, U> TryInto<U> for T where U: TryFrom<T> {
    type Err = U::Err;

    fn try_into(self) -> Result<U, U::Err> {
        U::try_from(self)
    }
}

////////////////////////////////////////////////////////////////////////////////
// CONCRETE IMPLS
////////////////////////////////////////////////////////////////////////////////

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsRef<[T]> for [T] {
    fn as_ref(&self) -> &[T] {
        self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsMut<[T]> for [T] {
    fn as_mut(&mut self) -> &mut [T] {
        self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<str> for str {
    #[inline]
    fn as_ref(&self) -> &str {
        self
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2014 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.

//! Exposes the NonZero lang item which provides optimization hints.
#![unstable(feature = "nonzero",
            reason = "needs an RFC to flesh out the design",
            issue = "27730")]

use marker::Sized;
use ops::{CoerceUnsized, Deref};

/// Unsafe trait to indicate what types are usable with the NonZero struct
pub unsafe trait Zeroable {}

unsafe impl<T:?Sized> Zeroable for *const T {}
unsafe impl<T:?Sized> Zeroable for *mut T {}
unsafe impl Zeroable for isize {}
unsafe impl Zeroable for usize {}
unsafe impl Zeroable for i8 {}
unsafe impl Zeroable for u8 {}
unsafe impl Zeroable for i16 {}
unsafe impl Zeroable for u16 {}
unsafe impl Zeroable for i32 {}
unsafe impl Zeroable for u32 {}
unsafe impl Zeroable for i64 {}
unsafe impl Zeroable for u64 {}

/// A wrapper type for raw pointers and integers that will never be
/// NULL or 0 that might allow certain optimizations.
#[lang = "non_zero"]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub struct NonZero<T: Zeroable>(T);

impl<T: Zeroable> NonZero<T> {
    /// Creates an instance of NonZero with the provided value.
    /// You must indeed ensure that the value is actually "non-zero".
    #[inline(always)]
    pub unsafe fn new(inner: T) -> NonZero<T> {
        NonZero(inner)
    }
}

impl<T: Zeroable> Deref for NonZero<T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        let NonZero(ref inner) = *self;
        inner
    }
}

impl<T: Zeroable+CoerceUnsized<U>, U: Zeroable> CoerceUnsized<NonZero<U>> for NonZero<T> {}
<commit_msg>Auto merge of #29085 - petrochenkov:nonzero, r=alexcrichton<commit_after>// Copyright 2012-2014 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.

//! Exposes the NonZero lang item which provides optimization hints.
#![unstable(feature = "nonzero",
            reason = "needs an RFC to flesh out the design",
            issue = "27730")]

use marker::Sized;
use ops::{CoerceUnsized, Deref};

/// Unsafe trait to indicate what types are usable with the NonZero struct
pub unsafe trait Zeroable {}

unsafe impl<T:?Sized> Zeroable for *const T {}
unsafe impl<T:?Sized> Zeroable for *mut T {}
unsafe impl Zeroable for isize {}
unsafe impl Zeroable for usize {}
unsafe impl Zeroable for i8 {}
unsafe impl Zeroable for u8 {}
unsafe impl Zeroable for i16 {}
unsafe impl Zeroable for u16 {}
unsafe impl Zeroable for i32 {}
unsafe impl Zeroable for u32 {}
unsafe impl Zeroable for i64 {}
unsafe impl Zeroable for u64 {}

/// A wrapper type for raw pointers and integers that will never be
/// NULL or 0 that might allow certain optimizations.
#[lang = "non_zero"]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub struct NonZero<T: Zeroable>(T);

#[cfg(stage0)]
macro_rules! nonzero_new {
    () => (
        /// Creates an instance of NonZero with the provided value.
        /// You must indeed ensure that the value is actually "non-zero".
        #[inline(always)]
        pub unsafe fn new(inner: T) -> NonZero<T> {
            NonZero(inner)
        }
    )
}
#[cfg(not(stage0))]
macro_rules! nonzero_new {
    () => (
        /// Creates an instance of NonZero with the provided value.
        /// You must indeed ensure that the value is actually "non-zero".
        #[inline(always)]
        pub unsafe const fn new(inner: T) -> NonZero<T> {
            NonZero(inner)
        }
    )
}

impl<T: Zeroable> NonZero<T> {
    nonzero_new!{}
}

impl<T: Zeroable> Deref for NonZero<T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        let NonZero(ref inner) = *self;
        inner
    }
}

impl<T: Zeroable+CoerceUnsized<U>, U: Zeroable> CoerceUnsized<NonZero<U>> for NonZero<T> {}
<|endoftext|>


<commit_before>#![feature(rustc_private)]
extern crate llvm_sys as llvm;
extern crate libc;
use std::ptr;
use std::ffi;

use self::llvm::prelude::{LLVMContextRef, LLVMModuleRef, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef};
use self::llvm::core::*;
use self::llvm::target::*;
use self::llvm::target_machine::*;

use std::collections::{HashMap};
use std::mem;

use syntax::ast::{Block, Expr, Decl, TType, OptionalTypeExprTupleList};
use syntax::ptr::{B};
//FIXME this import is for integration testing purposes
use syntax::parse::*;//{Parser};
use syntax::parse::parser::{Parser};
use link::link;
use helpers::*;

pub struct Context{
    context : LLVMContextRef,
    pub module : LLVMModuleRef,
    builder : LLVMBuilderRef,
    sym_tab : HashMap<String, LLVMValueRef>,
    bb_stack : Vec<*mut llvm::LLVMBasicBlock>
}

impl Context{
    fn new(module_name : &str) -> Self{
        unsafe{
            let llvm_context =  LLVMContextCreate();
            let llvm_module = LLVMModuleCreateWithNameInContext(c_str_ptr!(module_name),
                                                                llvm_context);
            let builder = LLVMCreateBuilderInContext(llvm_context);
            let sym_tab = HashMap::new();
            let bb_stack = Vec::new();

            Context {
                context : llvm_context,
                module : llvm_module,
                builder : builder,
                sym_tab : sym_tab,
                bb_stack : bb_stack
            }
        }
    }

    pub fn dump(&self){
        unsafe{
            LLVMDumpModule(self.module);
        }
    }
}

impl Drop for Context{
    fn drop(&mut self){
        unsafe{
            LLVMDisposeBuilder(self.builder);
            LLVMDisposeModule(self.module);
            LLVMContextDispose(self.context);
        }
    }
}

//TODO move these in a seperate file
type IRBuildingResult = Result<LLVMValueRef, String>;

trait IRBuilder{
    fn codegen(&self, ctxt : &mut Context) -> IRBuildingResult;
}

fn std_functions_call_factory(fn_name : &str,
                              args : &OptionalTypeExprTupleList,
                              ctxt : &mut Context) -> Option<LLVMValueRef>{
    unsafe{
        match fn_name {
            "print" =>{
                debug_assert!(args.is_some(), "No args passed to print()");
                let lst = args.as_ref().unwrap();
                debug_assert!(lst.len() == 1, "One arg should be passed to print()");
                debug_assert!(lst[0].0 == TType::TString);
                let str_arg = match &*lst[0].1 {
                    &Expr::StringExpr(ref value) => c_str_ptr!(&*(value.clone())),
                    _ => panic!("Expected a string expr")
                };

                let print_ty = LLVMIntTypeInContext(ctxt.context, 32);
                let mut pf_type_args_vec = Vec::new();
                pf_type_args_vec.push(LLVMPointerType(LLVMIntTypeInContext(ctxt.context, 8),
                                                      0));
                let proto = LLVMFunctionType(print_ty, pf_type_args_vec.as_mut_ptr(), 1, 1);
                let print_function = LLVMAddFunction(ctxt.module,
                                                     c_str_ptr!("printf"),
                                                     proto);
                let gstr = LLVMBuildGlobalStringPtr(ctxt.builder,
                                                    str_arg,
                                                    c_str_ptr!(".str"));
                let mut pf_args = Vec::new();
                pf_args.push(gstr);

                Some(LLVMBuildCall(ctxt.builder,
                                   print_function,
                                   pf_args.as_mut_ptr(),
                                   1,
                                   c_str_ptr!("call")))
            },
            _ => {None}
        }
    }
}

fn get_llvm_type_for_ttype(ty : &TType, ctxt : &mut Context) -> LLVMTypeRef{
    unsafe{
        match ty {
            &TType::TVoid => LLVMVoidTypeInContext(ctxt.context),
            &TType::TInt32 => LLVMIntTypeInContext(ctxt.context, 32),
            _ => panic!("Other TTypes not mapped yet to the corresponding LLVM types")
        }
    }
}

impl IRBuilder for Expr{
    fn codegen(&self, ctxt : &mut Context) -> IRBuildingResult{
        macro_rules! build_binary_instrs{
            ($fun : ident, $e1:ident, $e2:ident, $s : expr) => {{
                let ev1 = try!($e1.codegen(ctxt));
                let ev2 = try!($e2.codegen(ctxt));
                Ok($fun(ctxt.builder, ev1, ev2, $s.as_ptr() as *const i8))
            }}
        }
        unsafe{
            match self{
                &Expr::NumExpr(ref i) => {
                    let ty = LLVMIntTypeInContext(ctxt.context, 32);
                    Ok(LLVMConstInt(ty, *i as u64, 0))
                },
                &Expr::AddExpr(ref e1, ref e2) => {
                    build_binary_instrs!(LLVMBuildFAdd, e1, e2, "add_tmp")
                },
                &Expr::SubExpr(ref e1, ref e2) => {
                    build_binary_instrs!(LLVMBuildFSub, e1, e2, "sub_tmp")
                },
                &Expr::MulExpr(ref e1, ref e2) => {
                    build_binary_instrs!(LLVMBuildFMul, e1, e2, "mul_tmp")
                },
                &Expr::DivExpr(ref e1, ref e2) => {
                    build_binary_instrs!(LLVMBuildFDiv, e1, e2, "div_tmp")
                },
                &Expr::IfThenElseExpr(ref conditional_expr, ref then_expr, ref else_expr) => {
                    let cond_code = try!(conditional_expr.codegen(ctxt));
                    let zero = LLVMConstInt(LLVMIntTypeInContext(ctxt.context, 32), 0u64, 0);
                    let if_cond = LLVMBuildICmp(ctxt.builder, llvm::LLVMIntPredicate::LLVMIntNE, cond_code, zero, c_str_ptr!("ifcond"));
                    let bb = LLVMGetInsertBlock(ctxt.builder);
                    let function = LLVMGetBasicBlockParent(bb);
                    let then_block = LLVMAppendBasicBlockInContext(ctxt.context, function, c_str_ptr!("thencond"));
                    let else_block = LLVMAppendBasicBlockInContext(ctxt.context, function, c_str_ptr!("elsecond"));
                    let ifcont_block = LLVMAppendBasicBlockInContext(ctxt.context, function, c_str_ptr!("ifcont"));
                    LLVMBuildCondBr(ctxt.builder, if_cond, then_block, else_block);

                    LLVMPositionBuilderAtEnd(ctxt.builder, then_block);
                    let then_code = try!(then_expr.codegen(ctxt));
                    LLVMBuildBr(ctxt.builder, ifcont_block);
                    let then_end = LLVMGetInsertBlock(ctxt.builder);

                    LLVMPositionBuilderAtEnd(ctxt.builder, else_block);
                    let else_code = try!(else_expr.codegen(ctxt));
                    LLVMBuildBr(ctxt.builder, ifcont_block);
                    let else_end = LLVMGetInsertBlock(ctxt.builder);

                    LLVMPositionBuilderAtEnd(ctxt.builder, ifcont_block);

                    let phi_node = LLVMBuildPhi(ctxt.builder, LLVMIntTypeInContext(ctxt.context, 32), c_str_ptr!("ifphi"));
                    LLVMAddIncoming(phi_node, vec![then_code].as_mut_ptr(), vec![then_end].as_mut_ptr(), 1);
                    LLVMAddIncoming(phi_node, vec![else_code].as_mut_ptr(), vec![else_end].as_mut_ptr(), 1);
                    Ok(phi_node)

                },
                &Expr::CallExpr(ref fn_name, ref optional_args) => {
                    //FIXME instead of directly passing to the factory
                    //fn_name can be checked in a map that records names of std functions
                    match std_functions_call_factory(&*fn_name, optional_args, ctxt) {
                        Some(call) => Ok(call),
                        _ => {
                            //user defined function call
                            let mut pf_args = Vec::new();
                            //FIXME pass args if present in the call
                            if optional_args.is_some() {

                            }
                            //pf_args.push(gstr);
                            let _fn = ctxt.sym_tab[&*fn_name];
                            Ok(LLVMBuildCall(ctxt.builder,
                                            _fn,
                                            pf_args.as_mut_ptr(),
                                            0,
                                            c_str_ptr!("")))
                        }
                    }
                },
                &Expr::LetExpr(ref decls, ref expr) => {
                    debug_assert!(!decls.is_empty(), "Declarations in a let block can't be empty");
                    debug_assert!(expr.is_some(), "Expr in a let block can't be empty");
                    for decl in &*decls {
                        match decl {
                            &Decl::FunDec(ref name, ref params, ref ty, ref body, ref body_ty) => {
                                let llvm_ty = get_llvm_type_for_ttype(ty, ctxt);
                                let proto = LLVMFunctionType(llvm_ty, ptr::null_mut(), 0, 0);
                                let function = LLVMAddFunction(ctxt.module,
                                                               c_str_ptr!(&(*name.clone())),
                                                               proto);
                                let bb = LLVMAppendBasicBlockInContext(ctxt.context,
                                                                       function,
                                                                       c_str_ptr!("entry"));
                                ctxt.sym_tab.insert(name.clone(), function);
                                LLVMPositionBuilderAtEnd(ctxt.builder, bb);
                                //trans_expr(body, &mut ctxt);
                                let value_ref = try!(body.codegen(ctxt));
                                if *ty == TType::TVoid{
                                    LLVMBuildRetVoid(ctxt.builder);
                                }
                                else{
                                    LLVMBuildRet(ctxt.builder, value_ref);
                                }
                            },
                            _ => panic!("More decl types should be covered")
                        }

                    }
                    //trans_expr(&*expr.unwrap(), &mut ctxt);
                    //FIXME should the previous bb be popped here?
                    let bb = ctxt.bb_stack.pop().unwrap();
                    LLVMPositionBuilderAtEnd(ctxt.builder, bb);
                    let e = &expr.as_ref().unwrap();
                    let v = try!(e.codegen(ctxt));
                    Ok(v)
                }
                t => Err(format!("error: {:?}", t))
            }
        }
    }
}

pub fn translate(expr : &Expr) -> Option<Context>{
    let mut ctxt = Context::new("main_mod");
    unsafe{
        let r = LLVM_InitializeNativeTarget();
        assert_eq!(r, 0);
        LLVM_InitializeNativeAsmPrinter();
        //build outer embedding main() fn
        let ty = LLVMIntTypeInContext(ctxt.context, 32);
        let proto = LLVMFunctionType(ty, ptr::null_mut(), 0, 0);
        let function = LLVMAddFunction(ctxt.module,
                                       c_str_ptr!("main"),
                                       proto);
        let bb = LLVMAppendBasicBlockInContext(ctxt.context,
                                               function,
                                               c_str_ptr!("entry"));
        LLVMPositionBuilderAtEnd(ctxt.builder, bb);
        ctxt.bb_stack.push(bb);
        trans_expr(expr, &mut ctxt);

        //exit function
        let exit_ty = LLVMVoidTypeInContext(ctxt.context);
        let mut exit_type_args_vec = Vec::new();
        exit_type_args_vec.push(LLVMIntTypeInContext(ctxt.context, 32));
        let exit_proto = LLVMFunctionType(exit_ty, exit_type_args_vec.as_mut_ptr(), 1, 0);
        let exit_function = LLVMAddFunction(ctxt.module,
                                                      ffi::CString::new("exit").unwrap().as_ptr(),
                                                      exit_proto);
        let mut exit_args = Vec::new();
        exit_args.push(LLVMConstInt(LLVMIntTypeInContext(ctxt.context, 32), 0 as u64, 0));
        LLVMBuildCall(ctxt.builder,
                                  exit_function,
                                  exit_args.as_mut_ptr(),
                                  1,
                                  ffi::CString::new("call").unwrap().as_ptr());
        LLVMBuildRet(ctxt.builder,
                     LLVMConstInt(LLVMIntTypeInContext(ctxt.context, 32), 0 as u64, 0));

        //add translated code as part of the block

    }
    Some(ctxt)
}

fn trans_expr(expr: &Expr, ctxt : &mut Context){
    let result = expr.codegen(ctxt); //ctxt is already &mut
    match result {
        Ok(_) => {},
        Err(msg) => panic!(msg)
    }
}

//#[test]
fn test_translate_std_print_call() {
    let ctxt = translate(&Expr::CallExpr("print".to_string(),
                                  Some(vec![(TType::TString,
                                             B(Expr::StringExpr("abhi".to_string())))])));
    assert_eq!(ctxt.is_some(), true);
    ctxt.unwrap().dump();
}

//#[test]
fn test_prsr_bcknd_intgrtion_prnt_call() {
    let mut p = Parser::new("print(\"Grrrr!\n\")".to_string());
    p.start_lexer();
    let tup = p.expr();
    let (ty, b_expr) = tup.unwrap();
    let ctxt = translate(&*b_expr);
    // let ctxt = translate();&Expr::CallExpr("print".to_string(),
    //                               Some(vec![(TType::TString,
    //                                          B(Expr::StringExpr("abhi".to_string())))])));
    assert_eq!(ctxt.is_some(), true);
    ctxt.unwrap().dump();
}

#[test]
fn test_translate_add_expr(){
    let mut p = Parser::new(String::from("let function foo() : int = 1+3 in foo() end"));
    p.start_lexer();
    let tup = p.expr();
    let (_ , b_expr) = tup.unwrap();
    let ctxt = translate(&*b_expr);
    ctxt.unwrap().dump();
}
#[test]
fn test_prsr_bcknd_intgrtion_let_blk() {
    let mut p = Parser::new("let function foo() = print(\"Grrrr!\n\") in foo() end".to_string());
    p.start_lexer();
    let tup = p.expr();
    let (ty, b_expr) = tup.unwrap();
    let ctxt = translate(&*b_expr);
    assert_eq!(ctxt.is_some(), true);
    ctxt.unwrap().dump();
}

#[test]
fn test_prsr_bcknd_intgrtion_if_then_expr() {
    let mut p = Parser::new("let function foo() :int = if 1+1 then 1 else 5 in foo() end".to_string());
    p.start_lexer();
    let tup = p.expr();
    let (ty, b_expr) = tup.unwrap();
    let ctxt = translate(&*b_expr);
    assert_eq!(ctxt.is_some(), true);
    ctxt.unwrap().dump();
}

//#[test]
//fn test_prsr_bcknd_intgrtion_for_expr() {
//    let mut p = Parser::new("let function foo() = for i:= 1 to 1 do 1 in foo() end".to_string());
//    p.start_lexer();
//    let tup = p.expr();
//    let (ty, b_expr) = tup.unwrap();
//    let ctxt = translate(&*b_expr);
//    assert_eq!(ctxt.is_some(), true);
//    ctxt.unwrap().dump();
//}
<commit_msg>Add call to link in translate<commit_after>#![feature(rustc_private)]
extern crate llvm_sys as llvm;
extern crate libc;
use std::ptr;
use std::ffi;

use self::llvm::prelude::{LLVMContextRef, LLVMModuleRef, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef};
use self::llvm::core::*;
use self::llvm::target::*;
use self::llvm::target_machine::*;

use std::collections::{HashMap};
use std::mem;

use syntax::ast::{Block, Expr, Decl, TType, OptionalTypeExprTupleList};
use syntax::ptr::{B};
//FIXME this import is for integration testing purposes
use syntax::parse::*;//{Parser};
use syntax::parse::parser::{Parser};
use link::link;
use helpers::*;

pub struct Context{
    context : LLVMContextRef,
    pub module : LLVMModuleRef,
    builder : LLVMBuilderRef,
    sym_tab : HashMap<String, LLVMValueRef>,
    bb_stack : Vec<*mut llvm::LLVMBasicBlock>
}

impl Context{
    fn new(module_name : &str) -> Self{
        unsafe{
            let llvm_context =  LLVMContextCreate();
            let llvm_module = LLVMModuleCreateWithNameInContext(c_str_ptr!(module_name),
                                                                llvm_context);
            let builder = LLVMCreateBuilderInContext(llvm_context);
            let sym_tab = HashMap::new();
            let bb_stack = Vec::new();

            Context {
                context : llvm_context,
                module : llvm_module,
                builder : builder,
                sym_tab : sym_tab,
                bb_stack : bb_stack
            }
        }
    }

    pub fn dump(&self){
        unsafe{
            LLVMDumpModule(self.module);
        }
    }
}

impl Drop for Context{
    fn drop(&mut self){
        unsafe{
            LLVMDisposeBuilder(self.builder);
            LLVMDisposeModule(self.module);
            LLVMContextDispose(self.context);
        }
    }
}

//TODO move these in a seperate file
type IRBuildingResult = Result<LLVMValueRef, String>;

trait IRBuilder{
    fn codegen(&self, ctxt : &mut Context) -> IRBuildingResult;
}

fn std_functions_call_factory(fn_name : &str,
                              args : &OptionalTypeExprTupleList,
                              ctxt : &mut Context) -> Option<LLVMValueRef>{
    unsafe{
        match fn_name {
            "print" =>{
                debug_assert!(args.is_some(), "No args passed to print()");
                let lst = args.as_ref().unwrap();
                debug_assert!(lst.len() == 1, "One arg should be passed to print()");
                debug_assert!(lst[0].0 == TType::TString);
                let str_arg = match &*lst[0].1 {
                    &Expr::StringExpr(ref value) => c_str_ptr!(&*(value.clone())),
                    _ => panic!("Expected a string expr")
                };

                let print_ty = LLVMIntTypeInContext(ctxt.context, 32);
                let mut pf_type_args_vec = Vec::new();
                pf_type_args_vec.push(LLVMPointerType(LLVMIntTypeInContext(ctxt.context, 8),
                                                      0));
                let proto = LLVMFunctionType(print_ty, pf_type_args_vec.as_mut_ptr(), 1, 1);
                let print_function = LLVMAddFunction(ctxt.module,
                                                     c_str_ptr!("printf"),
                                                     proto);
                let gstr = LLVMBuildGlobalStringPtr(ctxt.builder,
                                                    str_arg,
                                                    c_str_ptr!(".str"));
                let mut pf_args = Vec::new();
                pf_args.push(gstr);

                Some(LLVMBuildCall(ctxt.builder,
                                   print_function,
                                   pf_args.as_mut_ptr(),
                                   1,
                                   c_str_ptr!("call")))
            },
            _ => {None}
        }
    }
}

fn get_llvm_type_for_ttype(ty : &TType, ctxt : &mut Context) -> LLVMTypeRef{
    unsafe{
        match ty {
            &TType::TVoid => LLVMVoidTypeInContext(ctxt.context),
            &TType::TInt32 => LLVMIntTypeInContext(ctxt.context, 32),
            _ => panic!("Other TTypes not mapped yet to the corresponding LLVM types")
        }
    }
}

impl IRBuilder for Expr{
    fn codegen(&self, ctxt : &mut Context) -> IRBuildingResult{
        macro_rules! build_binary_instrs{
            ($fun : ident, $e1:ident, $e2:ident, $s : expr) => {{
                let ev1 = try!($e1.codegen(ctxt));
                let ev2 = try!($e2.codegen(ctxt));
                Ok($fun(ctxt.builder, ev1, ev2, $s.as_ptr() as *const i8))
            }}
        }
        unsafe{
            match self{
                &Expr::NumExpr(ref i) => {
                    let ty = LLVMIntTypeInContext(ctxt.context, 32);
                    Ok(LLVMConstInt(ty, *i as u64, 0))
                },
                &Expr::AddExpr(ref e1, ref e2) => {
                    build_binary_instrs!(LLVMBuildFAdd, e1, e2, "add_tmp")
                },
                &Expr::SubExpr(ref e1, ref e2) => {
                    build_binary_instrs!(LLVMBuildFSub, e1, e2, "sub_tmp")
                },
                &Expr::MulExpr(ref e1, ref e2) => {
                    build_binary_instrs!(LLVMBuildFMul, e1, e2, "mul_tmp")
                },
                &Expr::DivExpr(ref e1, ref e2) => {
                    build_binary_instrs!(LLVMBuildFDiv, e1, e2, "div_tmp")
                },
                &Expr::IfThenElseExpr(ref conditional_expr, ref then_expr, ref else_expr) => {
                    let cond_code = try!(conditional_expr.codegen(ctxt));
                    let zero = LLVMConstInt(LLVMIntTypeInContext(ctxt.context, 32), 0u64, 0);
                    let if_cond = LLVMBuildICmp(ctxt.builder, llvm::LLVMIntPredicate::LLVMIntNE, cond_code, zero, c_str_ptr!("ifcond"));
                    let bb = LLVMGetInsertBlock(ctxt.builder);
                    let function = LLVMGetBasicBlockParent(bb);
                    let then_block = LLVMAppendBasicBlockInContext(ctxt.context, function, c_str_ptr!("thencond"));
                    let else_block = LLVMAppendBasicBlockInContext(ctxt.context, function, c_str_ptr!("elsecond"));
                    let ifcont_block = LLVMAppendBasicBlockInContext(ctxt.context, function, c_str_ptr!("ifcont"));
                    LLVMBuildCondBr(ctxt.builder, if_cond, then_block, else_block);

                    LLVMPositionBuilderAtEnd(ctxt.builder, then_block);
                    let then_code = try!(then_expr.codegen(ctxt));
                    LLVMBuildBr(ctxt.builder, ifcont_block);
                    let then_end = LLVMGetInsertBlock(ctxt.builder);

                    LLVMPositionBuilderAtEnd(ctxt.builder, else_block);
                    let else_code = try!(else_expr.codegen(ctxt));
                    LLVMBuildBr(ctxt.builder, ifcont_block);
                    let else_end = LLVMGetInsertBlock(ctxt.builder);

                    LLVMPositionBuilderAtEnd(ctxt.builder, ifcont_block);

                    let phi_node = LLVMBuildPhi(ctxt.builder, LLVMIntTypeInContext(ctxt.context, 32), c_str_ptr!("ifphi"));
                    LLVMAddIncoming(phi_node, vec![then_code].as_mut_ptr(), vec![then_end].as_mut_ptr(), 1);
                    LLVMAddIncoming(phi_node, vec![else_code].as_mut_ptr(), vec![else_end].as_mut_ptr(), 1);
                    Ok(phi_node)

                },
                &Expr::CallExpr(ref fn_name, ref optional_args) => {
                    //FIXME instead of directly passing to the factory
                    //fn_name can be checked in a map that records names of std functions
                    match std_functions_call_factory(&*fn_name, optional_args, ctxt) {
                        Some(call) => Ok(call),
                        _ => {
                            //user defined function call
                            let mut pf_args = Vec::new();
                            //FIXME pass args if present in the call
                            if optional_args.is_some() {

                            }
                            //pf_args.push(gstr);
                            let _fn = ctxt.sym_tab[&*fn_name];
                            Ok(LLVMBuildCall(ctxt.builder,
                                            _fn,
                                            pf_args.as_mut_ptr(),
                                            0,
                                            c_str_ptr!("")))
                        }
                    }
                },
                &Expr::LetExpr(ref decls, ref expr) => {
                    debug_assert!(!decls.is_empty(), "Declarations in a let block can't be empty");
                    debug_assert!(expr.is_some(), "Expr in a let block can't be empty");
                    for decl in &*decls {
                        match decl {
                            &Decl::FunDec(ref name, ref params, ref ty, ref body, ref body_ty) => {
                                let llvm_ty = get_llvm_type_for_ttype(ty, ctxt);
                                let proto = LLVMFunctionType(llvm_ty, ptr::null_mut(), 0, 0);
                                let function = LLVMAddFunction(ctxt.module,
                                                               c_str_ptr!(&(*name.clone())),
                                                               proto);
                                let bb = LLVMAppendBasicBlockInContext(ctxt.context,
                                                                       function,
                                                                       c_str_ptr!("entry"));
                                ctxt.sym_tab.insert(name.clone(), function);
                                LLVMPositionBuilderAtEnd(ctxt.builder, bb);
                                //trans_expr(body, &mut ctxt);
                                let value_ref = try!(body.codegen(ctxt));
                                if *ty == TType::TVoid{
                                    LLVMBuildRetVoid(ctxt.builder);
                                }
                                else{
                                    LLVMBuildRet(ctxt.builder, value_ref);
                                }
                            },
                            _ => panic!("More decl types should be covered")
                        }

                    }
                    //trans_expr(&*expr.unwrap(), &mut ctxt);
                    //FIXME should the previous bb be popped here?
                    let bb = ctxt.bb_stack.pop().unwrap();
                    LLVMPositionBuilderAtEnd(ctxt.builder, bb);
                    let e = &expr.as_ref().unwrap();
                    let v = try!(e.codegen(ctxt));
                    Ok(v)
                }
                t => Err(format!("error: {:?}", t))
            }
        }
    }
}

pub fn translate(expr : &Expr) -> Option<Context>{
    let mut ctxt = Context::new("main_mod");
    unsafe{
        let r = LLVM_InitializeNativeTarget();
        assert_eq!(r, 0);
        LLVM_InitializeNativeAsmPrinter();
        //build outer embedding main() fn
        let ty = LLVMIntTypeInContext(ctxt.context, 32);
        let proto = LLVMFunctionType(ty, ptr::null_mut(), 0, 0);
        let function = LLVMAddFunction(ctxt.module,
                                       c_str_ptr!("main"),
                                       proto);
        let bb = LLVMAppendBasicBlockInContext(ctxt.context,
                                               function,
                                               c_str_ptr!("entry"));
        LLVMPositionBuilderAtEnd(ctxt.builder, bb);
        ctxt.bb_stack.push(bb);
        trans_expr(expr, &mut ctxt);

        //exit function
        let exit_ty = LLVMVoidTypeInContext(ctxt.context);
        let mut exit_type_args_vec = Vec::new();
        exit_type_args_vec.push(LLVMIntTypeInContext(ctxt.context, 32));
        let exit_proto = LLVMFunctionType(exit_ty, exit_type_args_vec.as_mut_ptr(), 1, 0);
        let exit_function = LLVMAddFunction(ctxt.module,
                                                      ffi::CString::new("exit").unwrap().as_ptr(),
                                                      exit_proto);
        let mut exit_args = Vec::new();
        exit_args.push(LLVMConstInt(LLVMIntTypeInContext(ctxt.context, 32), 0 as u64, 0));
        LLVMBuildCall(ctxt.builder,
                                  exit_function,
                                  exit_args.as_mut_ptr(),
                                  1,
                                  ffi::CString::new("call").unwrap().as_ptr());
        LLVMBuildRet(ctxt.builder,
                     LLVMConstInt(LLVMIntTypeInContext(ctxt.context, 32), 0 as u64, 0));

        //add translated code as part of the block
        link(&ctxt);
    }
    Some(ctxt)
}

fn trans_expr(expr: &Expr, ctxt : &mut Context){
    let result = expr.codegen(ctxt); //ctxt is already &mut
    match result {
        Ok(_) => {},
        Err(msg) => panic!(msg)
    }
}

//#[test]
fn test_translate_std_print_call() {
    let ctxt = translate(&Expr::CallExpr("print".to_string(),
                                  Some(vec![(TType::TString,
                                             B(Expr::StringExpr("abhi".to_string())))])));
    assert_eq!(ctxt.is_some(), true);
    ctxt.unwrap().dump();
}

//#[test]
fn test_prsr_bcknd_intgrtion_prnt_call() {
    let mut p = Parser::new("print(\"Grrrr!\n\")".to_string());
    p.start_lexer();
    let tup = p.expr();
    let (ty, b_expr) = tup.unwrap();
    let ctxt = translate(&*b_expr);
    // let ctxt = translate();&Expr::CallExpr("print".to_string(),
    //                               Some(vec![(TType::TString,
    //                                          B(Expr::StringExpr("abhi".to_string())))])));
    assert_eq!(ctxt.is_some(), true);
    ctxt.unwrap().dump();
}

#[test]
fn test_translate_add_expr(){
    let mut p = Parser::new(String::from("let function foo() : int = 1+3 in foo() end"));
    p.start_lexer();
    let tup = p.expr();
    let (_ , b_expr) = tup.unwrap();
    let ctxt = translate(&*b_expr);
    ctxt.unwrap().dump();
}
#[test]
fn test_prsr_bcknd_intgrtion_let_blk() {
    let mut p = Parser::new("let function foo() = print(\"Grrrr!\n\") in foo() end".to_string());
    p.start_lexer();
    let tup = p.expr();
    let (ty, b_expr) = tup.unwrap();
    let ctxt = translate(&*b_expr);
    assert_eq!(ctxt.is_some(), true);
    ctxt.unwrap().dump();
}

#[test]
fn test_prsr_bcknd_intgrtion_if_then_expr() {
    let mut p = Parser::new("let function foo() :int = if 1+1 then 1 else 5 in foo() end".to_string());
    p.start_lexer();
    let tup = p.expr();
    let (ty, b_expr) = tup.unwrap();
    let ctxt = translate(&*b_expr);
    assert_eq!(ctxt.is_some(), true);
    ctxt.unwrap().dump();
}

//#[test]
//fn test_prsr_bcknd_intgrtion_for_expr() {
//    let mut p = Parser::new("let function foo() = for i:= 1 to 1 do 1 in foo() end".to_string());
//    p.start_lexer();
//    let tup = p.expr();
//    let (ty, b_expr) = tup.unwrap();
//    let ctxt = translate(&*b_expr);
//    assert_eq!(ctxt.is_some(), true);
//    ctxt.unwrap().dump();
//}
<|endoftext|>