<commit_before>use byteorder::{ReadBytesExt, LittleEndian};
use rwinstructs::timestamp::{WinTimestamp};
use rwinstructs::guid::{Guid};
use rshellitems::shellitem::{ShellItem};
use lnkpkg::locationinfo::{LocationInfo};
use lnkpkg::datablocks::{ExtraDataBlocks};
use lnkpkg::flags::{DataFlags,FileFlags};
use lnkpkg::flags;
use lnkpkg::errors::{LnkError};
use lnkpkg::utils;
use std::io::Read;
use std::io::Seek;

#[derive(Serialize,Debug)]
// 76 bytes long,
pub struct ShellLinkHeader {
    pub header_size: u32,
    pub guid: Guid,
    pub data_flags: DataFlags,
    pub file_flags: FileFlags,
    pub created: WinTimestamp,
    pub accessed: WinTimestamp,
    pub modified: WinTimestamp,
    pub file_size: u32,
    pub icon_offset: i32,
    pub window_flag: u32,
    pub hot_key: u16,
    pub unknown1: u16,
    pub unknown2: u32,
    pub unknown3: u32
}
impl ShellLinkHeader {
    pub fn new<R: Read>(mut reader: R) -> Result<ShellLinkHeader,LnkError> {
        let header_size = reader.read_u32::<LittleEndian>()?;
        let mut guid = Guid([0; 16]);
        reader.read_exact(&mut guid.0)?;

        let data_flags = DataFlags::from_bits_truncate(
            reader.read_u32::<LittleEndian>()?
        );

        let file_flags = FileFlags::from_bits_truncate(
            reader.read_u32::<LittleEndian>()?
        );
        let created = WinTimestamp(reader.read_u64::<LittleEndian>()?);
        let accessed = WinTimestamp(reader.read_u64::<LittleEndian>()?);
        let modified = WinTimestamp(reader.read_u64::<LittleEndian>()?);
        let file_size = reader.read_u32::<LittleEndian>()?;
        let icon_offset = reader.read_i32::<LittleEndian>()?;
        let window_flag = reader.read_u32::<LittleEndian>()?;
        let hot_key = reader.read_u16::<LittleEndian>()?;
        let unknown1 = reader.read_u16::<LittleEndian>()?;
        let unknown2 = reader.read_u32::<LittleEndian>()?;
        let unknown3 = reader.read_u32::<LittleEndian>()?;

        Ok(
            ShellLinkHeader {
                header_size: header_size,
                guid: guid,
                data_flags: data_flags,
                file_flags: file_flags,
                created: created,
                accessed: accessed,
                modified: modified,
                file_size: file_size,
                icon_offset: icon_offset,
                window_flag: window_flag,
                hot_key: hot_key,
                unknown1: unknown1,
                unknown2: unknown2,
                unknown3: unknown3
            }
        )
    }

    pub fn get_data_flags(&self) -> DataFlags {
        self.data_flags
    }
}

#[derive(Serialize,Debug)]
pub struct TargetIdList {
    pub list_size: u16,
    pub shell_items: Vec<ShellItem>
}

impl TargetIdList{
    pub fn new<R: Read>(mut reader: R) -> Result<TargetIdList, LnkError> {
        let list_size = reader.read_u16::<LittleEndian>()?;
        let mut shell_items: Vec<ShellItem> = Vec::new();

        let mut total_read: u16 = 0;
        while total_read < list_size {
            let shell_item = ShellItem::new(&mut reader)?;
            let size = shell_item.get_size();
            total_read += size;

            if size == 0 {
                // Null shell item is terminator
                break
            }

            shell_items.push(shell_item);
        }

        Ok(
            TargetIdList {
                list_size: list_size,
                shell_items: shell_items
            }
        )
    }

    pub fn get_size(&self) -> u16 {
        self.list_size
    }
}

#[derive(Serialize,Debug)]
pub struct DataStrings {
    pub description: Option<String>,
    pub relative_path: Option<String>,
    pub working_directory: Option<String>,
    pub command_line_args: Option<String>,
    pub icon_location: Option<String>
}
impl DataStrings {
    pub fn new<R: Read>(mut reader: R, data_flags: DataFlags) -> Result<DataStrings,LnkError> {
        let unicode_flag = data_flags.contains(flags::IS_UNICODE);

        let mut description = None;
        if data_flags.contains(flags::HAS_NAME) {
            if unicode_flag {
                description = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                description = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut relative_path = None;
        if data_flags.contains(flags::HAS_RELATIVE_PATH) {
            if unicode_flag {
                relative_path = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                relative_path = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut working_directory = None;
        if data_flags.contains(flags::HAS_WORKING_DIR) {
            if unicode_flag {
                working_directory = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                working_directory = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut command_line_args = None;
        if data_flags.contains(flags::HAS_ARGUMENTS) {
            if unicode_flag {
                command_line_args = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                command_line_args = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut icon_location = None;
        if data_flags.contains(flags::HAS_ICON_LOCATION) {
            if unicode_flag {
                icon_location = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                icon_location = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        Ok(
            DataStrings {
                description: description,
                relative_path: relative_path,
                working_directory: working_directory,
                command_line_args: command_line_args,
                icon_location: icon_location
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct Lnk {
    pub header: ShellLinkHeader,
    pub target_list: Option<TargetIdList>,
    pub location_info: Option<LocationInfo>,
    pub data_strings: DataStrings,
    pub extra_data: ExtraDataBlocks
}

impl Lnk {
    pub fn new<Rs: Read+Seek>(mut reader: Rs) -> Result<Lnk,LnkError> {
        let header = ShellLinkHeader::new(&mut reader)?;
        let header_flags = header.get_data_flags();

        let mut target_list = None;
        if header_flags.contains(flags::HAS_TARGET_ID_LIST) {
            // println!("target_list starting offset: {}",reader.seek(SeekFrom::Current(0))?);
            target_list = Some(TargetIdList::new(&mut reader)?);
        }

        let mut location_info = None;
        if header_flags.contains(flags::HAS_LINK_INFO) {
            // println!("location_info starting offset: {}",reader.seek(SeekFrom::Current(0))?);
            location_info = Some(LocationInfo::new(&mut reader)?);
        }

        // println!("data_strings starting offset: {}",reader.seek(SeekFrom::Current(0))?);
        let data_strings = DataStrings::new(
            &mut reader,
            header_flags
        )?;

        let extra_data = ExtraDataBlocks::new(&mut reader)?;

        Ok(
            Lnk {
                header: header,
                target_list: target_list,
                location_info: location_info,
                data_strings: data_strings,
                extra_data: extra_data
            }
        )
    }
}
<commit_msg>Switched TargetIdList over to using rshellitems::shelllist::ShellList::new to parsing the list of shell items to centralize shell item/list parsing.<commit_after>use byteorder::{ReadBytesExt, LittleEndian};
use rwinstructs::timestamp::{WinTimestamp};
use rwinstructs::guid::{Guid};
use rshellitems::shellitem::{ShellItem};
use rshellitems::shelllist::{ShellList};
use lnkpkg::locationinfo::{LocationInfo};
use lnkpkg::datablocks::{ExtraDataBlocks};
use lnkpkg::flags::{DataFlags,FileFlags};
use lnkpkg::flags;
use lnkpkg::errors::{LnkError};
use lnkpkg::utils;
use std::io::Read;
use std::io::Seek;
use std::io::Cursor;

#[derive(Serialize,Debug)]
// 76 bytes long,
pub struct ShellLinkHeader {
    pub header_size: u32,
    pub guid: Guid,
    pub data_flags: DataFlags,
    pub file_flags: FileFlags,
    pub created: WinTimestamp,
    pub accessed: WinTimestamp,
    pub modified: WinTimestamp,
    pub file_size: u32,
    pub icon_offset: i32,
    pub window_flag: u32,
    pub hot_key: u16,
    pub unknown1: u16,
    pub unknown2: u32,
    pub unknown3: u32
}
impl ShellLinkHeader {
    pub fn new<R: Read>(mut reader: R) -> Result<ShellLinkHeader,LnkError> {
        let header_size = reader.read_u32::<LittleEndian>()?;
        let mut guid = Guid([0; 16]);
        reader.read_exact(&mut guid.0)?;

        let data_flags = DataFlags::from_bits_truncate(
            reader.read_u32::<LittleEndian>()?
        );

        let file_flags = FileFlags::from_bits_truncate(
            reader.read_u32::<LittleEndian>()?
        );
        let created = WinTimestamp(reader.read_u64::<LittleEndian>()?);
        let accessed = WinTimestamp(reader.read_u64::<LittleEndian>()?);
        let modified = WinTimestamp(reader.read_u64::<LittleEndian>()?);
        let file_size = reader.read_u32::<LittleEndian>()?;
        let icon_offset = reader.read_i32::<LittleEndian>()?;
        let window_flag = reader.read_u32::<LittleEndian>()?;
        let hot_key = reader.read_u16::<LittleEndian>()?;
        let unknown1 = reader.read_u16::<LittleEndian>()?;
        let unknown2 = reader.read_u32::<LittleEndian>()?;
        let unknown3 = reader.read_u32::<LittleEndian>()?;

        Ok(
            ShellLinkHeader {
                header_size: header_size,
                guid: guid,
                data_flags: data_flags,
                file_flags: file_flags,
                created: created,
                accessed: accessed,
                modified: modified,
                file_size: file_size,
                icon_offset: icon_offset,
                window_flag: window_flag,
                hot_key: hot_key,
                unknown1: unknown1,
                unknown2: unknown2,
                unknown3: unknown3
            }
        )
    }

    pub fn get_data_flags(&self) -> DataFlags {
        self.data_flags
    }
}

#[derive(Serialize,Debug)]
pub struct TargetIdList {
    pub list_size: u16,
    pub shell_items: ShellList
}

impl TargetIdList{
    pub fn new<R: Read>(mut reader: R) -> Result<TargetIdList, LnkError> {
        let list_size = reader.read_u16::<LittleEndian>()?;
        let mut buffer = vec![0; list_size as usize];
        reader.read_exact(&mut buffer)?;

        let mut shell_items = ShellList::new(
            Cursor::new(buffer)
        )?;

        Ok(
            TargetIdList {
                list_size: list_size,
                shell_items: shell_items
            }
        )
    }

    pub fn get_size(&self) -> u16 {
        self.list_size
    }
}

#[derive(Serialize,Debug)]
pub struct DataStrings {
    pub description: Option<String>,
    pub relative_path: Option<String>,
    pub working_directory: Option<String>,
    pub command_line_args: Option<String>,
    pub icon_location: Option<String>
}
impl DataStrings {
    pub fn new<R: Read>(mut reader: R, data_flags: DataFlags) -> Result<DataStrings,LnkError> {
        let unicode_flag = data_flags.contains(flags::IS_UNICODE);

        let mut description = None;
        if data_flags.contains(flags::HAS_NAME) {
            if unicode_flag {
                description = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                description = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut relative_path = None;
        if data_flags.contains(flags::HAS_RELATIVE_PATH) {
            if unicode_flag {
                relative_path = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                relative_path = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut working_directory = None;
        if data_flags.contains(flags::HAS_WORKING_DIR) {
            if unicode_flag {
                working_directory = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                working_directory = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut command_line_args = None;
        if data_flags.contains(flags::HAS_ARGUMENTS) {
            if unicode_flag {
                command_line_args = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                command_line_args = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut icon_location = None;
        if data_flags.contains(flags::HAS_ICON_LOCATION) {
            if unicode_flag {
                icon_location = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                icon_location = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        Ok(
            DataStrings {
                description: description,
                relative_path: relative_path,
                working_directory: working_directory,
                command_line_args: command_line_args,
                icon_location: icon_location
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct Lnk {
    pub header: ShellLinkHeader,
    pub target_list: Option<TargetIdList>,
    pub location_info: Option<LocationInfo>,
    pub data_strings: DataStrings,
    pub extra_data: ExtraDataBlocks
}

impl Lnk {
    pub fn new<Rs: Read+Seek>(mut reader: Rs) -> Result<Lnk,LnkError> {
        let header = ShellLinkHeader::new(&mut reader)?;
        let header_flags = header.get_data_flags();

        let mut target_list = None;
        if header_flags.contains(flags::HAS_TARGET_ID_LIST) {
            // println!("target_list starting offset: {}",reader.seek(SeekFrom::Current(0))?);
            target_list = Some(TargetIdList::new(&mut reader)?);
        }

        let mut location_info = None;
        if header_flags.contains(flags::HAS_LINK_INFO) {
            // println!("location_info starting offset: {}",reader.seek(SeekFrom::Current(0))?);
            location_info = Some(LocationInfo::new(&mut reader)?);
        }

        // println!("data_strings starting offset: {}",reader.seek(SeekFrom::Current(0))?);
        let data_strings = DataStrings::new(
            &mut reader,
            header_flags
        )?;

        let extra_data = ExtraDataBlocks::new(&mut reader)?;

        Ok(
            Lnk {
                header: header,
                target_list: target_list,
                location_info: location_info,
                data_strings: data_strings,
                extra_data: extra_data
            }
        )
    }

    fn get_shell_list() {

    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::BufRead;
use std::io::Write;
use chrono::*;
use http_status::HttpStatus;

// http://stackoverflow.com/a/27590832/376138
macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

#[derive(Eq, PartialEq, Clone)]
#[derive(Debug)]
pub struct Request {
    pub id: i32,
    pub time: DateTime<FixedOffset>,
    pub url: String
}

impl Request {
    fn new_from_log_line(log_line: &String) -> Result<Request, &'static str> {
        let parts: Vec<&str> = log_line.split(" ").collect();

        let id = match parts.get(2) {
            Some(id) =>  id,
            None => return Err("Uncomprehensible request logline")
        };

        // Shortest valid id format is "[1]"
        if id.len() < 3 {
            return Err("Uncomprehensible request logline");
        }

        let id_parsed: i32 = match id[1..id.len()-1].parse() {
            Ok(id) =>  id,
            Err(_) => return Err("Uncomprehensible request logline")
        };

        let url = match parts.get(5) {
            Some(url) =>  url,
            None => return Err("Uncomprehensible request logline")
        };

        let date = &format!("{} {}", parts[0], parts[1]);

        let date_parsed = match DateTime::parse_from_str(date, "%d/%b/%Y:%H:%M:%S %z") {
            Ok(date_time) => date_time,
            Err(_) => return Err("Uncomprehensible request logline")
        };

        Ok(Request {
            id: id_parsed,
            time: date_parsed,
            url: url.to_string()
        })
    }
}

#[derive(Eq, PartialEq, Clone)]
#[derive(Debug)]
pub struct Response {
    pub id: i32,
    pub time: DateTime<FixedOffset>,
    pub mime_type: String,
    pub response_time: Duration,
    pub http_status: HttpStatus,
}

impl Response {
    fn new_from_log_line(log_line: &String) -> Result<Response, &'static str> {
        let parts: Vec<&str> = log_line.split(" ").collect();

        let id = parts[2];

        // Shortest valid id format is "[1]"
        if id.len() < 3 {
            return Err("Uncomprehensible response logline");
        }

        let id_numeric: i32 = match id[1..id.len()-1].parse() {
            Ok(number) => number,
            Err(_) => return Err("Uncomprehensible response logline")
        };

        let time = match DateTime::parse_from_str(&format!("{} {}", parts[0], parts[1]), "%d/%b/%Y:%H:%M:%S %z") {
            Ok(time) => time,
            Err(_) => return Err("Uncomprehensible response logline")
        };

        let response_time = parts[parts.len()-1];
        if response_time.len() < 3 {
            return Err("Uncomprehensible response logline");
        }

        let response_time_duration = match response_time[0..response_time.len()-2].parse() {
            Ok(number) => Duration::milliseconds(number),
            Err(_) => return Err("Uncomprehensible response logline")
        };

        // Handle special case where the mime type sometimes contains
        // a space, so we need to re-assemble it
        let mime_type = match parts.len() {
            8 => format!("{} {}", parts[5], parts[6]),
            _ => parts[5].to_string()
        };

        let status_code = match parts[4].parse() {
            Ok(number) => HttpStatus::from_code(number),
            Err(_) => return Err("Uncomprehensible response logline")
        };

        Ok(Response {
            id: id_numeric,
            time: time,
            response_time: response_time_duration,
            mime_type: mime_type,
            http_status: status_code,
        })
    }
}

pub fn parse(reader: &mut io::Read) -> Result<(Vec<Request>,Vec<Response>), &'static str> {
    let input = io::BufReader::new(reader);

    let mut requests: Vec<Request> = Vec::new();
    let mut responses: Vec<Response> = Vec::new();

    for line in input.lines() {
        let line_value = &line.unwrap();

        if line_value.contains("->") {
            match Request::new_from_log_line(&line_value) {
                Ok(r) => {
                    // if time_filter.is_none() ||
                    //   (time_filter.is_some() && r.is_between_times(UTC::now().with_timezone(&r.time.timezone()) - time_filter.unwrap(), UTC::now().with_timezone(&r.time.timezone()))) {
                        requests.push(r);
                    // }
                },
                Err(err) => println_stderr!("Skipped a line: {}", err)
            }
        }

        if line_value.contains("<-") {
            match Response::new_from_log_line(&line_value) {
                Ok(r) => responses.push(r),
                Err(err) => println_stderr!("Skipped a line: {}", err)
            }
        }

    }

    responses.sort_by_key(|r| r.id);

    Ok((requests, responses))
}

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

    #[test]
    fn test_parse_simple() {
        let mut input_reader = File::open("src/test/simple-1.log").unwrap();

        let (requests, responses) = parse(&mut input_reader).unwrap();

        assert_eq!(requests.len(), 2);
        assert_eq!(responses.len(), 2);
    }
}
<commit_msg>Extract test for common scenario, DRY<commit_after>use std::io;
use std::io::BufRead;
use std::io::Write;
use chrono::*;
use http_status::HttpStatus;

// http://stackoverflow.com/a/27590832/376138
macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

#[derive(Eq, PartialEq, Clone)]
#[derive(Debug)]
pub struct Request {
    pub id: i32,
    pub time: DateTime<FixedOffset>,
    pub url: String
}

impl Request {
    fn new_from_log_line(log_line: &String) -> Result<Request, &'static str> {
        let parts: Vec<&str> = log_line.split(" ").collect();

        let id = match parts.get(2) {
            Some(id) =>  id,
            None => return Err("Uncomprehensible request logline")
        };

        // Shortest valid id format is "[1]"
        if id.len() < 3 {
            return Err("Uncomprehensible request logline");
        }

        let id_parsed: i32 = match id[1..id.len()-1].parse() {
            Ok(id) =>  id,
            Err(_) => return Err("Uncomprehensible request logline")
        };

        let url = match parts.get(5) {
            Some(url) =>  url,
            None => return Err("Uncomprehensible request logline")
        };

        let date = &format!("{} {}", parts[0], parts[1]);

        let date_parsed = match DateTime::parse_from_str(date, "%d/%b/%Y:%H:%M:%S %z") {
            Ok(date_time) => date_time,
            Err(_) => return Err("Uncomprehensible request logline")
        };

        Ok(Request {
            id: id_parsed,
            time: date_parsed,
            url: url.to_string()
        })
    }
}

#[derive(Eq, PartialEq, Clone)]
#[derive(Debug)]
pub struct Response {
    pub id: i32,
    pub time: DateTime<FixedOffset>,
    pub mime_type: String,
    pub response_time: Duration,
    pub http_status: HttpStatus,
}

impl Response {
    fn new_from_log_line(log_line: &String) -> Result<Response, &'static str> {
        let parts: Vec<&str> = log_line.split(" ").collect();

        let id = parts[2];

        // Shortest valid id format is "[1]"
        if id.len() < 3 {
            return Err("Uncomprehensible response logline");
        }

        let id_numeric: i32 = match id[1..id.len()-1].parse() {
            Ok(number) => number,
            Err(_) => return Err("Uncomprehensible response logline")
        };

        let time = match DateTime::parse_from_str(&format!("{} {}", parts[0], parts[1]), "%d/%b/%Y:%H:%M:%S %z") {
            Ok(time) => time,
            Err(_) => return Err("Uncomprehensible response logline")
        };

        let response_time = parts[parts.len()-1];
        if response_time.len() < 3 {
            return Err("Uncomprehensible response logline");
        }

        let response_time_duration = match response_time[0..response_time.len()-2].parse() {
            Ok(number) => Duration::milliseconds(number),
            Err(_) => return Err("Uncomprehensible response logline")
        };

        // Handle special case where the mime type sometimes contains
        // a space, so we need to re-assemble it
        let mime_type = match parts.len() {
            8 => format!("{} {}", parts[5], parts[6]),
            _ => parts[5].to_string()
        };

        let status_code = match parts[4].parse() {
            Ok(number) => HttpStatus::from_code(number),
            Err(_) => return Err("Uncomprehensible response logline")
        };

        Ok(Response {
            id: id_numeric,
            time: time,
            response_time: response_time_duration,
            mime_type: mime_type,
            http_status: status_code,
        })
    }
}

pub fn parse(reader: &mut io::Read) -> Result<(Vec<Request>,Vec<Response>), &'static str> {
    let input = io::BufReader::new(reader);

    let mut requests: Vec<Request> = Vec::new();
    let mut responses: Vec<Response> = Vec::new();

    for line in input.lines() {
        let line_value = &line.unwrap();

        if line_value.contains("->") {
            match Request::new_from_log_line(&line_value) {
                Ok(r) => {
                    // if time_filter.is_none() ||
                    //   (time_filter.is_some() && r.is_between_times(UTC::now().with_timezone(&r.time.timezone()) - time_filter.unwrap(), UTC::now().with_timezone(&r.time.timezone()))) {
                        requests.push(r);
                    // }
                },
                Err(err) => println_stderr!("Skipped a line: {}", err)
            }
        }

        if line_value.contains("<-") {
            match Response::new_from_log_line(&line_value) {
                Ok(r) => responses.push(r),
                Err(err) => println_stderr!("Skipped a line: {}", err)
            }
        }

    }

    responses.sort_by_key(|r| r.id);

    Ok((requests, responses))
}

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

    fn base_parsing_test(file_path: &str, expected_request_count: usize, expected_response_count: usize) -> (Vec<Request>,Vec<Response>) {
        let mut input_reader = File::open(file_path).unwrap();

        let (requests, responses) = parse(&mut input_reader).unwrap();

        assert_eq!(requests.len(), expected_request_count);
        assert_eq!(responses.len(), expected_response_count);

        (requests, responses)
    }

    #[test]
    fn test_parse_simple() {
        base_parsing_test("src/test/simple-1.log", 2, 2);
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::sync::Arc;

use rustfft::FFTplanner;
use common;
use dct1::*;
use dct2::*;
use dct2::dct2_butterflies::*;
use dct3::*;
use dct3::dct3_butterflies::*;
use dct4::*;
use mdct::*;

const DCT2_BUTTERFLIES: [usize; 4] = [2, 4, 8, 16];
const DCT3_BUTTERFLIES: [usize; 4] = [2, 4, 8, 16];

/// The DCT planner is used to make new DCT algorithm instances.
///
/// RustDCT has several DCT algorithms available for each DCT type; For a given DCT type and problem size, the FFTplanner
/// decides which of the available DCT algorithms to use and then initializes them.
///
/// ~~~
/// // Perform a DCT Type 4 of size 1234
/// use std::sync::Arc;
/// use rustdct::DCTplanner;
///
/// let mut input:  Vec<f32> = vec![0f32; 1234];
/// let mut output: Vec<f32> = vec![0f32; 1234];
///
/// let mut planner = DCTplanner::new();
/// let dct4 = planner.plan_dct4(1234);
/// dct4.process(&mut input, &mut output);
///
/// // The DCT instance returned by the planner is stored behind an `Arc`, so it's cheap to clone
/// let dct4_clone = Arc::clone(&dct4);
/// ~~~
///
/// If you plan on creating multiple DCT instances, it is recommnded to reuse the same planner for all of them. This
/// is because the planner re-uses internal data across DCT instances wherever possible, saving memory and reducing
/// setup time. (DCT instances created with one planner will never re-use data and buffers with DCT instances created
/// by a different planner)
///
/// Each DCT instance owns `Arc`s to its shared internal data, rather than borrowing it from the planner, so it's
/// perfectly safe to drop the planner after creating DCT instances.
pub struct DCTplanner<T> {
    fft_planner: FFTplanner<T>,
    dct2_cache: HashMap<usize, Arc<DCT2<T>>>,
    dct3_cache: HashMap<usize, Arc<DCT3<T>>>,
}
impl<T: common::DCTnum> DCTplanner<T> {
    pub fn new() -> Self {
        Self {
            fft_planner: FFTplanner::new(false),
            dct2_cache: HashMap::new(),
            dct3_cache: HashMap::new(),
        }
    }

    /// Returns a DCT Type 1 instance which processes signals of size `len`.
    /// If this is called multiple times, it will attempt to re-use internal data between instances
    pub fn plan_dct1(&mut self, len: usize) -> Arc<DCT1<T>> {
        //benchmarking shows that below about 25, it's faster to just use the naive DCT1 algorithm
        if len < 25 {
            Arc::new(DCT1Naive::new(len))
        } else {
            let fft = self.fft_planner.plan_fft((len - 1) * 2);
            Arc::new(DCT1ViaFFT::new(fft))
        }
    }

    /// Returns a DCT Type 2 instance which processes signals of size `len`.
    /// If this is called multiple times, it will attempt to re-use internal data between instances
    pub fn plan_dct2(&mut self, len: usize) -> Arc<DCT2<T>> {
        if self.dct2_cache.contains_key(&len) {
            Arc::clone(self.dct2_cache.get(&len).unwrap())
        } else {
            let result = self.plan_new_dct2(len);
            self.dct2_cache.insert(len, Arc::clone(&result));
            result
        }
    }

    fn plan_new_dct2(&mut self, len: usize) -> Arc<DCT2<T>> {
        if DCT2_BUTTERFLIES.contains(&len) {
            self.plan_dct2_butterfly(len)
        } else if len.is_power_of_two() && len > 2 {
            let half_dct = self.plan_dct2(len / 2);
            let quarter_dct = self.plan_dct2(len / 4);
            Arc::new(DCT2SplitRadix::new(half_dct, quarter_dct)) as Arc<DCT2<T>>
        } else if len < 16 {
            //benchmarking shows that below about 16, it's faster to just use the naive DCT2 algorithm
            Arc::new(DCT2Naive::new(len))
        } else {
            let fft = self.fft_planner.plan_fft(len);
            Arc::new(DCT2ViaFFT::new(fft))
        }
    }

    fn plan_dct2_butterfly(&mut self, len: usize) -> Arc<DCT2<T>> {
        match len {
            2 => Arc::new(DCT2Butterfly2::new()),
            4 => Arc::new(DCT2Butterfly4::new()),
            8 => Arc::new(DCT2Butterfly8::new()),
            16 => Arc::new(DCT2Butterfly16::new()),
            _ => panic!("Invalid butterfly size for DCT2: {}", len)
        }
    }

    /// Returns DCT Type 3 instance which processes signals of size `len`.
    /// If this is called multiple times, it will attempt to re-use internal data between instances
    pub fn plan_dct3(&mut self, len: usize) -> Arc<DCT3<T>> {
        if self.dct3_cache.contains_key(&len) {
            Arc::clone(self.dct3_cache.get(&len).unwrap())
        } else {
            let result = self.plan_new_dct3(len);
            self.dct3_cache.insert(len, Arc::clone(&result));
            result
        }
    }

    fn plan_new_dct3(&mut self, len: usize) -> Arc<DCT3<T>> {
        if DCT3_BUTTERFLIES.contains(&len) {
            self.plan_dct3_butterfly(len)
        } else if len.is_power_of_two() && len > 2 {
            let half_dct = self.plan_dct3(len / 2);
            let quarter_dct = self.plan_dct3(len / 4);
            Arc::new(DCT3SplitRadix::new(half_dct, quarter_dct)) as Arc<DCT3<T>>
        } else if len < 16 {
            //benchmarking shows that below about 16, it's faster to just use the naive DCT2 algorithm
            Arc::new(DCT3Naive::new(len))
        } else {
            let fft = self.fft_planner.plan_fft(len);
            Arc::new(DCT3ViaFFT::new(fft))
        }
    }

    fn plan_dct3_butterfly(&mut self, len: usize) -> Arc<DCT3<T>> {
        match len {
            2 => Arc::new(DCT3Butterfly2::new()),
            4 => Arc::new(DCT3Butterfly4::new()),
            8 => Arc::new(DCT3Butterfly8::new()),
            16 => Arc::new(DCT3Butterfly16::new()),
            _ => panic!("Invalid butterfly size for DCT3: {}", len)
        }
    }

    /// Returns a DCT Type 4 instance which processes signals of size `len`.
    /// If this is called multiple times, it will attempt to re-use internal data between instances
    pub fn plan_dct4(&mut self, len: usize) -> Arc<DCT4<T>> {

        //if we have an even size, we can use the DCT4 Via DCT3 algorithm
        if len % 2 == 0 {
            //benchmarking shows that below 6, it's faster to just use the naive DCT4 algorithm
            if len < 6 {
                Arc::new(DCT4Naive::new(len))
            } else {
                let inner_dct = self.plan_dct3(len / 2);
                Arc::new(DCT4ViaDCT3::new(inner_dct))
            }

        }
        else {
            //odd size, so we can use the "DCT4 via FFT odd" algorithm
            //benchmarking shows that below about 7, it's faster to just use the naive DCT4 algorithm
            if len < 7 {
                Arc::new(DCT4Naive::new(len))
            } else {
                let fft = self.fft_planner.plan_fft(len);
                Arc::new(DCT4ViaFFTOdd::new(fft))
            }
        }
    }

    /// Returns a MDCT instance which processes inputs of size ` len * 2` and produces outputs of size `len`.
    ///
    /// `window_fn` is a function that takes a `size` and returns a `Vec` containing `size` window values.
    /// See the [`window_fn`](mdct/window_fn/index.html) module for provided window functions.
    ///
    /// If this is called multiple times, it will attempt to re-use internal data between instances
    pub fn plan_mdct<F>(&mut self, len: usize, window_fn: F) -> Arc<MDCT<T>>
    where
        F: FnOnce(usize) -> Vec<T>,
    {
        //benchmarking shows that using the inner dct4 algorithm is always faster than computing the naive algorithm
        let inner_dct4 = self.plan_dct4(len);
        Arc::new(MDCTViaDCT4::new(inner_dct4, window_fn))
    }

    /// Returns an IMDCT instance which processes input of size `len` and produces outputs of size `len * 2`.
    ///
    /// `window_fn` is a function that takes a `size` and returns a `Vec` containing `size` window values.
    /// See the [`window_fn`](mdct/window_fn/index.html) module for provided window functions.
    ///
    /// If this is called multiple times, it will attempt to re-use internal data between instances
    pub fn plan_imdct<F>(&mut self, len: usize, window_fn: F) -> Arc<IMDCT<T>>
    where
        F: FnOnce(usize) -> Vec<T>,
    {
        //benchmarking shows that using the inner dct4 algorithm is always faster than computing the naive algorithm
        let inner_dct4 = self.plan_dct4(len);
        Arc::new(IMDCTViaDCT4::new(inner_dct4, window_fn))
    }
}
<commit_msg>Added a cache for all DCT types<commit_after>use std::collections::HashMap;
use std::sync::Arc;

use rustfft::FFTplanner;
use common;
use dct1::*;
use dct2::*;
use dct2::dct2_butterflies::*;
use dct3::*;
use dct3::dct3_butterflies::*;
use dct4::*;
use mdct::*;

const DCT2_BUTTERFLIES: [usize; 4] = [2, 4, 8, 16];
const DCT3_BUTTERFLIES: [usize; 4] = [2, 4, 8, 16];

/// The DCT planner is used to make new DCT algorithm instances.
///
/// RustDCT has several DCT algorithms available for each DCT type; For a given DCT type and problem size, the FFTplanner
/// decides which of the available DCT algorithms to use and then initializes them.
///
/// ~~~
/// // Perform a DCT Type 4 of size 1234
/// use std::sync::Arc;
/// use rustdct::DCTplanner;
///
/// let mut input:  Vec<f32> = vec![0f32; 1234];
/// let mut output: Vec<f32> = vec![0f32; 1234];
///
/// let mut planner = DCTplanner::new();
/// let dct4 = planner.plan_dct4(1234);
/// dct4.process(&mut input, &mut output);
///
/// // The DCT instance returned by the planner is stored behind an `Arc`, so it's cheap to clone
/// let dct4_clone = Arc::clone(&dct4);
/// ~~~
///
/// If you plan on creating multiple DCT instances, it is recommnded to reuse the same planner for all of them. This
/// is because the planner re-uses internal data across DCT instances wherever possible, saving memory and reducing
/// setup time. (DCT instances created with one planner will never re-use data and buffers with DCT instances created
/// by a different planner)
///
/// Each DCT instance owns `Arc`s to its shared internal data, rather than borrowing it from the planner, so it's
/// perfectly safe to drop the planner after creating DCT instances.
pub struct DCTplanner<T> {
    fft_planner: FFTplanner<T>,
    dct1_cache: HashMap<usize, Arc<DCT1<T>>>,
    dct2_cache: HashMap<usize, Arc<DCT2<T>>>,
    dct3_cache: HashMap<usize, Arc<DCT3<T>>>,
    dct4_cache: HashMap<usize, Arc<DCT4<T>>>,
    mdct_cache: HashMap<usize, Arc<MDCT<T>>>,
    imdct_cache: HashMap<usize, Arc<IMDCT<T>>>,
}
impl<T: common::DCTnum> DCTplanner<T> {
    pub fn new() -> Self {
        Self {
            fft_planner: FFTplanner::new(false),
            dct1_cache: HashMap::new(),
            dct2_cache: HashMap::new(),
            dct3_cache: HashMap::new(),
            dct4_cache: HashMap::new(),
            mdct_cache: HashMap::new(),
            imdct_cache: HashMap::new(),
        }
    }

    /// Returns a DCT Type 1 instance which processes signals of size `len`.
    /// If this is called multiple times, it will attempt to re-use internal data between instances
    pub fn plan_dct1(&mut self, len: usize) -> Arc<DCT1<T>> {
        if self.dct1_cache.contains_key(&len) {
            Arc::clone(self.dct1_cache.get(&len).unwrap())
        } else {
            let result = self.plan_new_dct1(len);
            self.dct1_cache.insert(len, Arc::clone(&result));
            result
        }
    }

    fn plan_new_dct1(&mut self, len: usize) -> Arc<DCT1<T>> {
        //benchmarking shows that below about 25, it's faster to just use the naive DCT1 algorithm
        if len < 25 {
            Arc::new(DCT1Naive::new(len))
        } else {
            let fft = self.fft_planner.plan_fft((len - 1) * 2);
            Arc::new(DCT1ViaFFT::new(fft))
        }
    }

    /// Returns a DCT Type 2 instance which processes signals of size `len`.
    /// If this is called multiple times, it will attempt to re-use internal data between instances
    pub fn plan_dct2(&mut self, len: usize) -> Arc<DCT2<T>> {
        if self.dct2_cache.contains_key(&len) {
            Arc::clone(self.dct2_cache.get(&len).unwrap())
        } else {
            let result = self.plan_new_dct2(len);
            self.dct2_cache.insert(len, Arc::clone(&result));
            result
        }
    }

    fn plan_new_dct2(&mut self, len: usize) -> Arc<DCT2<T>> {
        if DCT2_BUTTERFLIES.contains(&len) {
            self.plan_dct2_butterfly(len)
        } else if len.is_power_of_two() && len > 2 {
            let half_dct = self.plan_dct2(len / 2);
            let quarter_dct = self.plan_dct2(len / 4);
            Arc::new(DCT2SplitRadix::new(half_dct, quarter_dct)) as Arc<DCT2<T>>
        } else if len < 16 {
            //benchmarking shows that below about 16, it's faster to just use the naive DCT2 algorithm
            Arc::new(DCT2Naive::new(len))
        } else {
            let fft = self.fft_planner.plan_fft(len);
            Arc::new(DCT2ViaFFT::new(fft))
        }
    }

    fn plan_dct2_butterfly(&mut self, len: usize) -> Arc<DCT2<T>> {
        match len {
            2 => Arc::new(DCT2Butterfly2::new()),
            4 => Arc::new(DCT2Butterfly4::new()),
            8 => Arc::new(DCT2Butterfly8::new()),
            16 => Arc::new(DCT2Butterfly16::new()),
            _ => panic!("Invalid butterfly size for DCT2: {}", len)
        }
    }

    /// Returns DCT Type 3 instance which processes signals of size `len`.
    /// If this is called multiple times, it will attempt to re-use internal data between instances
    pub fn plan_dct3(&mut self, len: usize) -> Arc<DCT3<T>> {
        if self.dct3_cache.contains_key(&len) {
            Arc::clone(self.dct3_cache.get(&len).unwrap())
        } else {
            let result = self.plan_new_dct3(len);
            self.dct3_cache.insert(len, Arc::clone(&result));
            result
        }
    }

    fn plan_new_dct3(&mut self, len: usize) -> Arc<DCT3<T>> {
        if DCT3_BUTTERFLIES.contains(&len) {
            self.plan_dct3_butterfly(len)
        } else if len.is_power_of_two() && len > 2 {
            let half_dct = self.plan_dct3(len / 2);
            let quarter_dct = self.plan_dct3(len / 4);
            Arc::new(DCT3SplitRadix::new(half_dct, quarter_dct)) as Arc<DCT3<T>>
        } else if len < 16 {
            //benchmarking shows that below about 16, it's faster to just use the naive DCT2 algorithm
            Arc::new(DCT3Naive::new(len))
        } else {
            let fft = self.fft_planner.plan_fft(len);
            Arc::new(DCT3ViaFFT::new(fft))
        }
    }

    fn plan_dct3_butterfly(&mut self, len: usize) -> Arc<DCT3<T>> {
        match len {
            2 => Arc::new(DCT3Butterfly2::new()),
            4 => Arc::new(DCT3Butterfly4::new()),
            8 => Arc::new(DCT3Butterfly8::new()),
            16 => Arc::new(DCT3Butterfly16::new()),
            _ => panic!("Invalid butterfly size for DCT3: {}", len)
        }
    }

    /// Returns a DCT Type 4 instance which processes signals of size `len`.
    /// If this is called multiple times, it will attempt to re-use internal data between instances
    pub fn plan_dct4(&mut self, len: usize) -> Arc<DCT4<T>> {
        if self.dct4_cache.contains_key(&len) {
            Arc::clone(self.dct4_cache.get(&len).unwrap())
        } else {
            let result = self.plan_new_dct4(len);
            self.dct4_cache.insert(len, Arc::clone(&result));
            result
        }
    }

    pub fn plan_new_dct4(&mut self, len: usize) -> Arc<DCT4<T>> {
        //if we have an even size, we can use the DCT4 Via DCT3 algorithm
        if len % 2 == 0 {
            //benchmarking shows that below 6, it's faster to just use the naive DCT4 algorithm
            if len < 6 {
                Arc::new(DCT4Naive::new(len))
            } else {
                let inner_dct = self.plan_dct3(len / 2);
                Arc::new(DCT4ViaDCT3::new(inner_dct))
            }
        } else {
            //odd size, so we can use the "DCT4 via FFT odd" algorithm
            //benchmarking shows that below about 7, it's faster to just use the naive DCT4 algorithm
            if len < 7 {
                Arc::new(DCT4Naive::new(len))
            } else {
                let fft = self.fft_planner.plan_fft(len);
                Arc::new(DCT4ViaFFTOdd::new(fft))
            }
        }
    }

    /// Returns a MDCT instance which processes inputs of size ` len * 2` and produces outputs of size `len`.
    ///
    /// `window_fn` is a function that takes a `size` and returns a `Vec` containing `size` window values.
    /// See the [`window_fn`](mdct/window_fn/index.html) module for provided window functions.
    ///
    /// If this is called multiple times, it will attempt to re-use internal data between instances
    pub fn plan_mdct<F>(&mut self, len: usize, window_fn: F) -> Arc<MDCT<T>>
    where F: (FnOnce(usize) -> Vec<T>) {
        if self.mdct_cache.contains_key(&len) {
            Arc::clone(self.mdct_cache.get(&len).unwrap())
        } else {
            let result = self.plan_new_mdct(len, window_fn);
            self.mdct_cache.insert(len, Arc::clone(&result));
            result
        }
    }

    pub fn plan_new_mdct<F>(&mut self, len: usize, window_fn: F) -> Arc<MDCT<T>>
    where F: (FnOnce(usize) -> Vec<T>) {
        //benchmarking shows that using the inner dct4 algorithm is always faster than computing the naive algorithm
        let inner_dct4 = self.plan_dct4(len);
        Arc::new(MDCTViaDCT4::new(inner_dct4, window_fn))
    }

    /// Returns an IMDCT instance which processes input of size `len` and produces outputs of size `len * 2`.
    ///
    /// `window_fn` is a function that takes a `size` and returns a `Vec` containing `size` window values.
    /// See the [`window_fn`](mdct/window_fn/index.html) module for provided window functions.
    ///
    /// If this is called multiple times, it will attempt to re-use internal data between instances
    pub fn plan_imdct<F>(&mut self, len: usize, window_fn: F) -> Arc<IMDCT<T>>
    where F: (FnOnce(usize) -> Vec<T>) {
        if self.imdct_cache.contains_key(&len) {
            Arc::clone(self.imdct_cache.get(&len).unwrap())
        } else {
            let result = self.plan_new_imdct(len, window_fn);
            self.imdct_cache.insert(len, Arc::clone(&result));
            result
        }
    }

    pub fn plan_new_imdct<F>(&mut self, len: usize, window_fn: F) -> Arc<IMDCT<T>>
    where F: (FnOnce(usize) -> Vec<T>) {
        //benchmarking shows that using the inner dct4 algorithm is always faster than computing the naive algorithm
        let inner_dct4 = self.plan_dct4(len);
        Arc::new(IMDCTViaDCT4::new(inner_dct4, window_fn))
    }
}
<|endoftext|>


<commit_before>#[crate_type = "bin"];
#[feature(globs, managed_boxes)];

extern mod syntax;

pub mod types;
pub mod clangll;
pub mod clang;
pub mod gen;
pub mod main;
<commit_msg>Fix build for:<commit_after>#[crate_type = "bin"];
#[feature(globs, managed_boxes, quote)];

extern mod syntax;

pub mod types;
pub mod clangll;
pub mod clang;
pub mod gen;
pub mod main;
<|endoftext|>


<commit_before>// This file is part of rgtk.
//
// rgtk is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// rgtk is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

/*!

Bindings and wrappers for __GTK+__, __GLib__ and __Cairo__.

The various parts of __rgtk__ can be found in the submodules __gtk__, __gdk__, __glib__ and __cairo__.

Trait reexports
===============

For your conveniance the various traits of `rgtk` are reexported in the `rgtk::*`
namespace as `{Gtk/Gdk/Glib/Cairo}{trait_name}Trait` so you can just use...

```Rust
extern mod rgtk;
use rgtk::*;
```

...to easily access all the traits methods:

```Rust
let button = gtk::Button:new(); // trait gtk::traits::Button reexported as GtkButtonTrait,
                                // its trait methods can be accessed here.
```
*/

#![crate_name = "rgtk"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![feature(macro_rules)]
#![allow(dead_code)] // TODO: drop this
#![feature(unsafe_destructor)]
#![feature(associated_types)]

extern crate libc;

pub use glib::traits::Connect;
pub use gtk::traits::Widget           as GtkWidgetTrait;
pub use gtk::traits::Container        as GtkContainerTrait;
pub use gtk::traits::Window           as GtkWindowTrait;
pub use gtk::traits::Misc             as GtkMiscTrait;
pub use gtk::traits::Button           as GtkButtonTrait;
pub use gtk::traits::Label            as GtkLabelTrait;
pub use gtk::traits::Box              as GtkBoxTrait;
pub use gtk::traits::Orientable       as GtkOrientableTrait;
pub use gtk::traits::Frame            as GtkFrameTrait;
pub use gtk::traits::ToggleButton     as GtkToggleButtonTrait;
pub use gtk::traits::ScaleButton      as GtkScaleButtonTrait;
pub use gtk::traits::Entry            as GtkEntryTrait;
pub use gtk::traits::Bin              as GtkBinTrait;
pub use gtk::traits::ToolShell        as GtkToolShellTrait;
pub use gtk::traits::ToolItem         as GtkToolItemTrait;
pub use gtk::traits::ToolButton       as GtkToolButtonTrait;
pub use gtk::traits::ToggleToolButton as GtkToggleToolButtonTrait;
pub use gtk::traits::Dialog           as GtkDialogTrait;
pub use gtk::traits::ColorChooser     as GtkColorChooserTrait;
pub use gtk::traits::Scrollable       as GtkScrollableTrait;
pub use gtk::traits::FileChooser      as GtkFileChooserTrait;
pub use gtk::traits::FontChooser      as GtkFontChooserTrait;
pub use gtk::traits::AppChooser       as GtkAppChooserTrait;
pub use gtk::traits::Range            as GtkRangeTrait;
pub use gtk::traits::Editable         as GtkEditableTrait;
pub use gtk::traits::MenuShell        as GtkMenuShellTrait;
pub use gtk::traits::MenuItem         as GtkMenuItemTrait;
pub use gtk::traits::CheckMenuItem    as GtkCheckMenuItemTrait;
pub use gtk::traits::CellEditable     as GtkCellEditableTrait;
pub use gtk::traits::CellRenderer     as GtkCellRendererTrait;
pub use gtk::traits::Actionable       as GtkActionableTrait;
pub use gtk::traits::ComboBox         as GtkComboBoxTrait;
pub use gtk::widgets::GValuePublic    as GtkValuePublic;

#[doc(hidden)]
#[cfg(target_os="macos")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3.0")]
    #[link(name = "gio-2.0")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3.0")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

#[doc(hidden)]
#[cfg(target_os="linux")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3")]
    #[link(name = "gio-2.0")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

#[doc(hidden)]
#[cfg(target_os="windows")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3")]
    #[link(name = "gio-2.0")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

pub mod gtk;
pub mod cairo;
pub mod gdk;
pub mod glib;
<commit_msg>add forgotten traits in rgtk.rs + reorder<commit_after>// This file is part of rgtk.
//
// rgtk is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// rgtk is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

/*!

Bindings and wrappers for __GTK+__, __GLib__ and __Cairo__.

The various parts of __rgtk__ can be found in the submodules __gtk__, __gdk__, __glib__ and __cairo__.

Trait reexports
===============

For your conveniance the various traits of `rgtk` are reexported in the `rgtk::*`
namespace as `{Gtk/Gdk/Glib/Cairo}{trait_name}Trait` so you can just use...

```Rust
extern mod rgtk;
use rgtk::*;
```

...to easily access all the traits methods:

```Rust
let button = gtk::Button:new(); // trait gtk::traits::Button reexported as GtkButtonTrait,
                                // its trait methods can be accessed here.
```
*/

#![crate_name = "rgtk"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![feature(macro_rules)]
#![allow(dead_code)] // TODO: drop this
#![feature(unsafe_destructor)]
#![feature(associated_types)]

extern crate libc;

pub use glib::traits::Connect;
pub use gtk::widgets::GValuePublic;

pub use gtk::traits::Box as GtkBoxTrait;
pub use gtk::traits::Actionable as GtkActionableTrait;
pub use gtk::traits::AppChooser as GtkAppChooserTrait;
pub use gtk::traits::Bin as GtkBinTrait;
pub use gtk::traits::Button as GtkButtonTrait;
pub use gtk::traits::CellEditable as GtkCellEditableTrait;
pub use gtk::traits::CellRenderer as GtkCellRendererTrait;
pub use gtk::traits::CheckMenuItem as GtkCheckMenuItemTrait;
pub use gtk::traits::ColorChooser as GtkColorChooserTrait;
pub use gtk::traits::ComboBox as GtkComboBoxTrait;
pub use gtk::traits::Container as GtkContainerTrait;
pub use gtk::traits::Dialog as GtkDialogTrait;
pub use gtk::traits::Editable as GtkEditableTrait;
pub use gtk::traits::Entry as GtkEntryTrait;
pub use gtk::traits::FileChooser as GtkFileChooserTrait;
pub use gtk::traits::FontChooser as GtkFontChooserTrait;
pub use gtk::traits::Frame as GtkFrameTrait;
pub use gtk::traits::Label as GtkLabelTrait;
pub use gtk::traits::MenuItem as GtkMenuItemTrait;
pub use gtk::traits::MenuShell as GtkMenuShellTrait;
pub use gtk::traits::Misc as GtkMiscTrait;
pub use gtk::traits::Orientable as GtkOrientableTrait;
pub use gtk::traits::Range as GtkRangeTrait;
pub use gtk::traits::RecentChooser as GtkRecentChooserTrait;
pub use gtk::traits::ScaleButton as GtkScaleButtonTrait;
pub use gtk::traits::Scrollable as GtkScrollableTrait;
pub use gtk::traits::ScrolledWindow as GtkScrolledWindowTrait;
pub use gtk::traits::TextBuffer as GtkTextBufferTrait;
pub use gtk::traits::ToggleButton as GtkToggleButtonTrait;
pub use gtk::traits::ToggleToolButton as GtkToggleToolButtonTrait;
pub use gtk::traits::ToolButton as GtkToolButtonTrait;
pub use gtk::traits::ToolItem as GtkToolItemTrait;
pub use gtk::traits::ToolShell as GtkToolShellTrait;
pub use gtk::traits::Widget as GtkWidgetTrait;
pub use gtk::traits::Window as GtkWindowTrait;

#[doc(hidden)]
#[cfg(target_os="macos")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3.0")]
    #[link(name = "gio-2.0")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3.0")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

#[doc(hidden)]
#[cfg(target_os="linux")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3")]
    #[link(name = "gio-2.0")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

#[doc(hidden)]
#[cfg(target_os="windows")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3")]
    #[link(name = "gio-2.0")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

pub mod gtk;
pub mod cairo;
pub mod gdk;
pub mod glib;
<|endoftext|>


<commit_before>use syntax::ast;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::ptr::P;
use syntax::util::ThinVec;

use attr::AttrBuilder;
use expr::ExprBuilder;
use ident::ToIdent;
use invoke::{Invoke, Identity};
use item::ItemBuilder;
use mac::MacBuilder;
use pat::PatBuilder;
use ty::TyBuilder;

//////////////////////////////////////////////////////////////////////////////

pub struct StmtBuilder<F=Identity> {
    callback: F,
    span: Span,
}

impl StmtBuilder {
    pub fn new() -> StmtBuilder {
        StmtBuilder::with_callback(Identity)
    }
}

impl<F> StmtBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    pub fn with_callback(callback: F) -> Self {
        StmtBuilder {
            callback: callback,
            span: DUMMY_SP,
        }
    }

    pub fn build(self, stmt: ast::Stmt) -> F::Result {
        self.callback.invoke(stmt)
    }

    pub fn span(mut self, span: Span) -> Self {
        self.span = span;
        self
    }

    pub fn build_stmt_kind(self, stmt_: ast::StmtKind) -> F::Result {
        let stmt = ast::Stmt {
            id: ast::DUMMY_NODE_ID,
            node: stmt_,
            span: self.span,
        };
        self.build(stmt)
    }

    pub fn build_let(self,
                     pat: P<ast::Pat>,
                     ty: Option<P<ast::Ty>>,
                     init: Option<P<ast::Expr>>,
                     attrs: Vec<ast::Attribute>) -> F::Result {
        let local = ast::Local {
            pat: pat,
            ty: ty,
            init: init,
            id: ast::DUMMY_NODE_ID,
            span: self.span,
            attrs: ThinVec::from(attrs),
        };

        self.build_stmt_kind(ast::StmtKind::Local(P(local)))
    }

    pub fn let_(self) -> PatBuilder<Self> {
        let span = self.span;
        PatBuilder::with_callback(self).span(span)
    }

    pub fn let_id<I>(self, id: I) -> StmtLetBuilder<F>
        where I: ToIdent,
    {
        self.let_().id(id)
    }

    pub fn build_expr(self, expr: P<ast::Expr>) -> F::Result {
        self.build_stmt_kind(ast::StmtKind::Expr(expr))
    }

    pub fn expr(self) -> ExprBuilder<StmtExprBuilder<F>> {
        let span = self.span;
        ExprBuilder::with_callback(StmtExprBuilder(self)).span(span)
    }

    pub fn semi(self) -> ExprBuilder<StmtSemiBuilder<F>> {
        let span = self.span;
        ExprBuilder::with_callback(StmtSemiBuilder(self)).span(span)
    }

    pub fn build_item(self, item: P<ast::Item>) -> F::Result {
        self.build_stmt_kind(ast::StmtKind::Item(item))
    }

    pub fn item(self) -> ItemBuilder<StmtItemBuilder<F>> {
        let span = self.span;
        ItemBuilder::with_callback(StmtItemBuilder(self)).span(span)
    }

    pub fn build_mac(self,
                     mac: ast::Mac,
                     style: ast::MacStmtStyle,
                     attrs: Vec<ast::Attribute>) -> F::Result {
        let attrs = ThinVec::from(attrs);
        self.build_stmt_kind(ast::StmtKind::Mac(P((mac, style, attrs))))
    }

    pub fn mac(self) -> StmtMacBuilder<F> {
        StmtMacBuilder {
            builder: self,
            attrs: vec![],
        }
    }
}

impl<F> Invoke<P<ast::Pat>> for StmtBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = StmtLetBuilder<F>;

    fn invoke(self, pat: P<ast::Pat>) -> StmtLetBuilder<F> {
        StmtLetBuilder {
            builder: self,
            attrs: vec![],
            pat: pat,
        }
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtMacBuilder<F> {
    builder: StmtBuilder<F>,
    attrs: Vec<ast::Attribute>,
}

impl<F> StmtMacBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    pub fn with_attrs<I>(mut self, iter: I) -> Self
        where I: IntoIterator<Item=ast::Attribute>,
    {
        self.attrs.extend(iter);
        self
    }

    pub fn with_attr(mut self, attr: ast::Attribute) -> Self {
        self.attrs.push(attr);
        self
    }

    pub fn attr(self) -> AttrBuilder<Self> {
        AttrBuilder::with_callback(self)
    }

    pub fn style(self, style: ast::MacStmtStyle) -> MacBuilder<StmtMacStyleBuilder<F>> {
        let span = self.builder.span;
        MacBuilder::with_callback(StmtMacStyleBuilder {
            builder: self.builder,
            style: style,
            attrs: self.attrs,
        }).span(span)
    }
}

impl<F> Invoke<ast::Attribute> for StmtMacBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = Self;

    fn invoke(self, attr: ast::Attribute) -> Self {
        self.with_attr(attr)
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtMacStyleBuilder<F> {
    builder: StmtBuilder<F>,
    style: ast::MacStmtStyle,
    attrs: Vec<ast::Attribute>,
}

impl<F> Invoke<ast::Mac> for StmtMacStyleBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = F::Result;

    fn invoke(self, mac: ast::Mac) -> F::Result {
        self.builder.build_mac(mac, self.style, self.attrs)
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtExprBuilder<F>(StmtBuilder<F>);

impl<F> Invoke<P<ast::Expr>> for StmtExprBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = F::Result;

    fn invoke(self, expr: P<ast::Expr>) -> F::Result {
        self.0.build_expr(expr)
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtSemiBuilder<F>(StmtBuilder<F>);

impl<F> Invoke<P<ast::Expr>> for StmtSemiBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = F::Result;

    fn invoke(self, expr: P<ast::Expr>) -> F::Result {
        self.0.build_stmt_kind(ast::StmtKind::Semi(expr))
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtLetBuilder<F> {
    builder: StmtBuilder<F>,
    attrs: Vec<ast::Attribute>,
    pat: P<ast::Pat>,
}

impl<F> StmtLetBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    pub fn with_attrs<I>(mut self, iter: I) -> Self
        where I: IntoIterator<Item=ast::Attribute>,
    {
        self.attrs.extend(iter);
        self
    }

    pub fn with_attr(mut self, attr: ast::Attribute) -> Self {
        self.attrs.push(attr);
        self
    }

    pub fn attr(self) -> AttrBuilder<Self> {
        AttrBuilder::with_callback(self)
    }

    fn build_ty(self, ty: P<ast::Ty>) -> StmtLetTyBuilder<F> {
        StmtLetTyBuilder {
            builder: self.builder,
            attrs: self.attrs,
            pat: self.pat,
            ty: ty,
        }
    }

    pub fn ty(self) -> TyBuilder<Self> {
        let span = self.builder.span;
        TyBuilder::with_callback(self).span(span)
    }

    pub fn build_expr(self, init: P<ast::Expr>) -> F::Result {
        self.builder.build_let(self.pat, None, Some(init), self.attrs)
    }

    pub fn expr(self) -> ExprBuilder<Self> {
        ExprBuilder::with_callback(self)
    }

    pub fn build(self) -> F::Result {
        self.builder.build_let(self.pat, None, None, self.attrs)
    }
}

impl<F> Invoke<ast::Attribute> for StmtLetBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = Self;

    fn invoke(self, attr: ast::Attribute) -> Self {
        self.with_attr(attr)
    }
}

impl<F> Invoke<P<ast::Ty>> for StmtLetBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = StmtLetTyBuilder<F>;

    fn invoke(self, ty: P<ast::Ty>) -> StmtLetTyBuilder<F> {
        self.build_ty(ty)
    }
}

impl<F> Invoke<P<ast::Expr>> for StmtLetBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = F::Result;

    fn invoke(self, expr: P<ast::Expr>) -> F::Result {
        self.build_expr(expr)
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtLetTyBuilder<F> {
    builder: StmtBuilder<F>,
    attrs: Vec<ast::Attribute>,
    pat: P<ast::Pat>,
    ty: P<ast::Ty>,
}

impl<F> StmtLetTyBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    pub fn expr(self) -> ExprBuilder<Self> {
        ExprBuilder::with_callback(self)
    }

    pub fn build(self) -> F::Result {
        self.builder.build_let(self.pat, Some(self.ty), None, self.attrs)
    }
}

impl<F> Invoke<P<ast::Expr>> for StmtLetTyBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = F::Result;

    fn invoke(self, init: P<ast::Expr>) -> F::Result {
        self.builder.build_let(self.pat, Some(self.ty), Some(init), self.attrs)
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtItemBuilder<F>(StmtBuilder<F>);

impl<F> Invoke<P<ast::Item>> for StmtItemBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = F::Result;

    fn invoke(self, item: P<ast::Item>) -> F::Result {
        self.0.build_item(item)
    }
}
<commit_msg>Add helpers to pass option ty and exprs to stmt let<commit_after>use syntax::ast;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::ptr::P;
use syntax::util::ThinVec;

use attr::AttrBuilder;
use expr::ExprBuilder;
use ident::ToIdent;
use invoke::{Invoke, Identity};
use item::ItemBuilder;
use mac::MacBuilder;
use pat::PatBuilder;
use ty::TyBuilder;

//////////////////////////////////////////////////////////////////////////////

pub struct StmtBuilder<F=Identity> {
    callback: F,
    span: Span,
}

impl StmtBuilder {
    pub fn new() -> StmtBuilder {
        StmtBuilder::with_callback(Identity)
    }
}

impl<F> StmtBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    pub fn with_callback(callback: F) -> Self {
        StmtBuilder {
            callback: callback,
            span: DUMMY_SP,
        }
    }

    pub fn build(self, stmt: ast::Stmt) -> F::Result {
        self.callback.invoke(stmt)
    }

    pub fn span(mut self, span: Span) -> Self {
        self.span = span;
        self
    }

    pub fn build_stmt_kind(self, stmt_: ast::StmtKind) -> F::Result {
        let stmt = ast::Stmt {
            id: ast::DUMMY_NODE_ID,
            node: stmt_,
            span: self.span,
        };
        self.build(stmt)
    }

    pub fn build_let(self,
                     pat: P<ast::Pat>,
                     ty: Option<P<ast::Ty>>,
                     init: Option<P<ast::Expr>>,
                     attrs: Vec<ast::Attribute>) -> F::Result {
        let local = ast::Local {
            pat: pat,
            ty: ty,
            init: init,
            id: ast::DUMMY_NODE_ID,
            span: self.span,
            attrs: ThinVec::from(attrs),
        };

        self.build_stmt_kind(ast::StmtKind::Local(P(local)))
    }

    pub fn let_(self) -> PatBuilder<Self> {
        let span = self.span;
        PatBuilder::with_callback(self).span(span)
    }

    pub fn let_id<I>(self, id: I) -> StmtLetBuilder<F>
        where I: ToIdent,
    {
        self.let_().id(id)
    }

    pub fn build_expr(self, expr: P<ast::Expr>) -> F::Result {
        self.build_stmt_kind(ast::StmtKind::Expr(expr))
    }

    pub fn expr(self) -> ExprBuilder<StmtExprBuilder<F>> {
        let span = self.span;
        ExprBuilder::with_callback(StmtExprBuilder(self)).span(span)
    }

    pub fn semi(self) -> ExprBuilder<StmtSemiBuilder<F>> {
        let span = self.span;
        ExprBuilder::with_callback(StmtSemiBuilder(self)).span(span)
    }

    pub fn build_item(self, item: P<ast::Item>) -> F::Result {
        self.build_stmt_kind(ast::StmtKind::Item(item))
    }

    pub fn item(self) -> ItemBuilder<StmtItemBuilder<F>> {
        let span = self.span;
        ItemBuilder::with_callback(StmtItemBuilder(self)).span(span)
    }

    pub fn build_mac(self,
                     mac: ast::Mac,
                     style: ast::MacStmtStyle,
                     attrs: Vec<ast::Attribute>) -> F::Result {
        let attrs = ThinVec::from(attrs);
        self.build_stmt_kind(ast::StmtKind::Mac(P((mac, style, attrs))))
    }

    pub fn mac(self) -> StmtMacBuilder<F> {
        StmtMacBuilder {
            builder: self,
            attrs: vec![],
        }
    }
}

impl<F> Invoke<P<ast::Pat>> for StmtBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = StmtLetBuilder<F>;

    fn invoke(self, pat: P<ast::Pat>) -> StmtLetBuilder<F> {
        StmtLetBuilder {
            builder: self,
            attrs: vec![],
            pat: pat,
        }
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtMacBuilder<F> {
    builder: StmtBuilder<F>,
    attrs: Vec<ast::Attribute>,
}

impl<F> StmtMacBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    pub fn with_attrs<I>(mut self, iter: I) -> Self
        where I: IntoIterator<Item=ast::Attribute>,
    {
        self.attrs.extend(iter);
        self
    }

    pub fn with_attr(mut self, attr: ast::Attribute) -> Self {
        self.attrs.push(attr);
        self
    }

    pub fn attr(self) -> AttrBuilder<Self> {
        AttrBuilder::with_callback(self)
    }

    pub fn style(self, style: ast::MacStmtStyle) -> MacBuilder<StmtMacStyleBuilder<F>> {
        let span = self.builder.span;
        MacBuilder::with_callback(StmtMacStyleBuilder {
            builder: self.builder,
            style: style,
            attrs: self.attrs,
        }).span(span)
    }
}

impl<F> Invoke<ast::Attribute> for StmtMacBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = Self;

    fn invoke(self, attr: ast::Attribute) -> Self {
        self.with_attr(attr)
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtMacStyleBuilder<F> {
    builder: StmtBuilder<F>,
    style: ast::MacStmtStyle,
    attrs: Vec<ast::Attribute>,
}

impl<F> Invoke<ast::Mac> for StmtMacStyleBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = F::Result;

    fn invoke(self, mac: ast::Mac) -> F::Result {
        self.builder.build_mac(mac, self.style, self.attrs)
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtExprBuilder<F>(StmtBuilder<F>);

impl<F> Invoke<P<ast::Expr>> for StmtExprBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = F::Result;

    fn invoke(self, expr: P<ast::Expr>) -> F::Result {
        self.0.build_expr(expr)
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtSemiBuilder<F>(StmtBuilder<F>);

impl<F> Invoke<P<ast::Expr>> for StmtSemiBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = F::Result;

    fn invoke(self, expr: P<ast::Expr>) -> F::Result {
        self.0.build_stmt_kind(ast::StmtKind::Semi(expr))
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtLetBuilder<F> {
    builder: StmtBuilder<F>,
    attrs: Vec<ast::Attribute>,
    pat: P<ast::Pat>,
}

impl<F> StmtLetBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    pub fn with_attrs<I>(mut self, iter: I) -> Self
        where I: IntoIterator<Item=ast::Attribute>,
    {
        self.attrs.extend(iter);
        self
    }

    pub fn with_attr(mut self, attr: ast::Attribute) -> Self {
        self.attrs.push(attr);
        self
    }

    pub fn attr(self) -> AttrBuilder<Self> {
        AttrBuilder::with_callback(self)
    }

    pub fn build_option_ty(self, ty: Option<P<ast::Ty>>) -> StmtLetTyBuilder<F> {
        StmtLetTyBuilder {
            builder: self.builder,
            attrs: self.attrs,
            pat: self.pat,
            ty: ty,
        }
    }

    pub fn ty(self) -> TyBuilder<Self> {
        let span = self.builder.span;
        TyBuilder::with_callback(self).span(span)
    }

    pub fn build_expr(self, init: P<ast::Expr>) -> F::Result {
        self.builder.build_let(self.pat, None, Some(init), self.attrs)
    }

    pub fn expr(self) -> ExprBuilder<Self> {
        ExprBuilder::with_callback(self)
    }

    pub fn build(self) -> F::Result {
        self.builder.build_let(self.pat, None, None, self.attrs)
    }
}

impl<F> Invoke<ast::Attribute> for StmtLetBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = Self;

    fn invoke(self, attr: ast::Attribute) -> Self {
        self.with_attr(attr)
    }
}

impl<F> Invoke<P<ast::Ty>> for StmtLetBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = StmtLetTyBuilder<F>;

    fn invoke(self, ty: P<ast::Ty>) -> StmtLetTyBuilder<F> {
        self.build_option_ty(Some(ty))
    }
}

impl<F> Invoke<P<ast::Expr>> for StmtLetBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = F::Result;

    fn invoke(self, expr: P<ast::Expr>) -> F::Result {
        self.build_expr(expr)
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtLetTyBuilder<F> {
    builder: StmtBuilder<F>,
    attrs: Vec<ast::Attribute>,
    pat: P<ast::Pat>,
    ty: Option<P<ast::Ty>>,
}

impl<F> StmtLetTyBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    pub fn expr(self) -> ExprBuilder<Self> {
        ExprBuilder::with_callback(self)
    }

    pub fn build_option_expr(self, expr: Option<P<ast::Expr>>) -> F::Result {
        self.builder.build_let(self.pat, self.ty, expr, self.attrs)
    }

    pub fn build(self) -> F::Result {
        self.build_option_expr(None)
    }
}

impl<F> Invoke<P<ast::Expr>> for StmtLetTyBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = F::Result;

    fn invoke(self, init: P<ast::Expr>) -> F::Result {
        self.build_option_expr(Some(init))
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtItemBuilder<F>(StmtBuilder<F>);

impl<F> Invoke<P<ast::Item>> for StmtItemBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = F::Result;

    fn invoke(self, item: P<ast::Item>) -> F::Result {
        self.0.build_item(item)
    }
}
<|endoftext|>