<commit_before>//! Library for manipulating Game Maker Studio's "data.win" (GEN8) data files.

#![feature(read_exact, associated_consts, associated_type_defaults)]
#![warn(missing_docs, trivial_casts, trivial_numeric_casts)]

#[macro_use]
extern crate quick_error;
extern crate byteorder;
#[macro_use]
extern crate log;

mod gamedata_io;

pub use gamedata_io::{ReadError, StringReadError};

use std::io::{self, Read, Write};
use std::path;

/// The data of a Game Maker Studio game.
///
/// This is the collective information acquired from "data.win".
pub struct GameData {
    metadata: MetaData,
    options: Options,
    extn: Extn,
    /// The sounds of the game.
    pub sounds: Sounds,
    audio_groups: Option<AudioGroups>,
    sprites: Sprites,
    backgrounds: Backgrounds,
    paths: Paths,
    scripts: Scripts,
    shaders: Shaders,
    /// The fonts of the game.
    pub fonts: Fonts,
    timelines: Timelines,
    objects: Objects,
    rooms: Rooms,
    dafl: Dafl,
    tpag: Tpag,
    code: Code,
    variables: Variables,
    functions: Functions,
    /// The strings of the game.
    pub strings: Strings,
    textures: Textures,
    audio: Audio,
}

/// A reader that satisfies the requirements for reading a GameData.
pub trait GameDataRead: Read + io::Seek {}
impl<T: Read + io::Seek> GameDataRead for T {}
/// A writer that satisfies the requirements for writing a GameData.
pub trait GameDataWrite: Write + io::Seek {}
impl<T: Write + io::Seek> GameDataWrite for T {}

impl GameData {
    /// Reads a GameData from a reader.
    pub fn from_reader<R: GameDataRead>(reader: &mut R) -> Result<GameData, ReadError> {
        gamedata_io::read(reader)
    }
    /// Reads a GameData from a file.
    pub fn from_file<P: AsRef<path::Path>>(path: &P) -> Result<GameData, ReadError> {
        use std::fs::File;
        use std::io::BufReader;
        let file = try!(File::open(path));
        GameData::from_reader(&mut BufReader::new(file))
    }
    /// Writes self to a writer.
    pub fn write_to_writer<W: GameDataWrite>(&self, writer: &mut W) -> io::Result<()> {
        gamedata_io::write(self, writer)
    }
    /// Writes self to a file.
    pub fn save_to_file<P: AsRef<path::Path>>(&self, path: &P) -> io::Result<()> {
        use std::fs::File;
        use std::io::BufWriter;
        let file = try!(File::create(path));
        self.write_to_writer(&mut BufWriter::new(file))
    }
    /// Returns the window width of the game.
    pub fn window_width(&self) -> u32 {
        self.metadata.window_width
    }
    /// Returns the window height of the game.
    pub fn window_height(&self) -> u32 {
        self.metadata.window_height
    }
    /// Sets the window dimensions of the game.
    pub fn set_window_dimensions(&mut self, width: u32, height: u32) {
        self.metadata.window_width = width;
        self.metadata.window_height = height;
    }
    /// Returns the window title of the game.
    pub fn window_title(&self) -> &str {
        &self.strings.strings[self.metadata.window_title_index]
    }
    /// Sets the window title of the game.
    pub fn set_window_title<S: Into<String>>(&mut self, new: S) {
        self.strings.strings[self.metadata.window_title_index] = new.into();
    }
}

/// Contains various metadata, for example, the window width/height/title.
struct MetaData {
    unk1: u32, // Purpose unknown
    game_id_1_index: usize, // Some kind of game id
    default_index: usize, // Points to "Default"
    unk2: u32,
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
    unk7: u32,
    unk8: u32,
    game_id_2_index: usize, // Some kind of game id, identical to game_id_1
    unk9: u32,
    unk10: u32,
    unk11: u32,
    unk12: u32,
    window_width: u32,
    window_height: u32,
    unk13: u32,
    unk14: u32,
    unk15: u32,
    unk16: u32,
    unk17: u32,
    unk18: u32,
    unk19: u32,
    unk20: u32,
    window_title_index: usize,
    unknown: Vec<u32>,
}

/// Game Maker project Options
struct Options {
    unk1: u32, // Unknown
    unk2: u32, // Unknown
    icon_offset: u32, // Points to texture data (icon?)
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
    unk7: u32,
    unk8: u32,
    unk9: u32,
    unk10: u32,
    unk11: u32,
    unk12: u32,
    unk13: u32,
    unk14: u32,
    unk15: u32,
    constant1_name_index: usize, // Offset of the name of this constant in the string table
    constant2_name_index: usize, // Offset of the name of this constant in the string table
    constant3_name_index: usize, // Offset of the name of this constant in the string table
    constant4_name_index: usize, // Offset of the name of this constant in the string table
    constant5_name_index: usize, // Offset of the name of this constant in the string table
    constant6_name_index: usize, // Offset of the name of this constant in the string table
    constant7_name_index: usize, // Offset of the name of this constant in the string table
    constant8_name_index: usize, // Offset of the name of this constant in the string table
    constant9_name_index: usize, // Offset of the name of this constant in the string table
    constant10_name_index: usize, // Offset of the name of this constant in the string table
    constant11_name_index: usize, // Offset of the name of this constant in the string table
    constant12_name_index: usize, // Offset of the name of this constant in the string table
    constant13_name_index: usize, // Offset of the name of this constant in the string table
    constant14_name_index: usize, // Offset of the name of this constant in the string table
}

/// Purpose unknown.
struct Extn {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker sound.
pub struct Sound {
    /// Index of the name in the string table.
    pub name_index: usize,
    unk1: u32,
    /// Index of the extension in the string table.
    pub ext_index: usize,
    /// Index of the filename in the string table.
    pub filename_index: usize,
    unk2: u32,
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
}

/// A collection of sounds.
pub struct Sounds {
    /// The sounds.
    pub sounds: Vec<Sound>,
}

/// Collection of audio groups. Not present in all games.
struct AudioGroups {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of sprites.
struct Sprites {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of backgrounds.
struct Backgrounds {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of paths.
struct Paths {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker script.
struct Script {
    /// Index of the name of the script in the string table
    pub name_index: usize,
    unknown: u32, // Unknown
}

/// A collection of scripts.
struct Scripts {
    pub scripts: Vec<Script>,
}

/// A collection of shaders.
struct Shaders {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A font.
#[derive(Clone)]
pub struct Font {
    /// Index of the font's resource name in the string table.
    pub name_index: usize,
    /// Index of the font's font name in the string table.
    pub font_name_index: usize,
    /// Point size of the font.
    pub point_size: u32,
    data: Vec<u8>,
}

/// A collection of fonts.
pub struct Fonts {
    /// The fonts.
    pub fonts: Vec<Font>,
    unknown: Vec<u8>, // Unknown trailing data
}

/// A collection of timelines.
struct Timelines {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of objects.
struct Objects {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of rooms.
struct Rooms {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Purpose unknown.
struct Dafl {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Purpose unknown.
struct Tpag {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Something to do with code. Maybe code of scripts?
struct Code {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker variable.
struct Variable {
    /// Index of the name of the variable in the strings section.
    pub name_index: usize,
    unknown: u32, // Purpose unknown. Ranges from 1 to a few thousand.
    code_offset: u32, // Points into the code section
}

/// A collection of variables.
struct Variables {
    pub variables: Vec<Variable>,
}

/// A game maker function.
struct Function {
    /// Index of the name of the function in the strings section.
    pub name_index: usize,
    unknown: u32, // Purpose unknown. Ranges from 1 to a few thousand.
    code_offset: u32, // Points into the code section.
}

/// A collection of functions.
struct Functions {
    pub functions: Vec<Function>,
}

/// A collection of strings.
///
/// All strings are assumed to be valid UTF-8.
pub struct Strings {
    /// The vector holding the strings.
    pub strings: Vec<String>,
}

struct Texture {
    unknown: u32, // Purpose unknown. Always seems to be 1.
    offset: u32, // Offset of data in the texture data
}

/// A collection of textures.
struct Textures {
    pub textures: Vec<Texture>,
    texture_data: Vec<u8>,
}

struct AudioData {
    data: Vec<u8>,
}

/// A collection of audio data.
struct Audio {
    audio: Vec<AudioData>,
    offsets: Vec<u32>, // Audio data is not contiguous, so we need to store relative offsets
    size: u32, // Fuck it
}
<commit_msg>Make Sound Copy<commit_after>//! Library for manipulating Game Maker Studio's "data.win" (GEN8) data files.

#![feature(read_exact, associated_consts, associated_type_defaults)]
#![warn(missing_docs, trivial_casts, trivial_numeric_casts)]

#[macro_use]
extern crate quick_error;
extern crate byteorder;
#[macro_use]
extern crate log;

mod gamedata_io;

pub use gamedata_io::{ReadError, StringReadError};

use std::io::{self, Read, Write};
use std::path;

/// The data of a Game Maker Studio game.
///
/// This is the collective information acquired from "data.win".
pub struct GameData {
    metadata: MetaData,
    options: Options,
    extn: Extn,
    /// The sounds of the game.
    pub sounds: Sounds,
    audio_groups: Option<AudioGroups>,
    sprites: Sprites,
    backgrounds: Backgrounds,
    paths: Paths,
    scripts: Scripts,
    shaders: Shaders,
    /// The fonts of the game.
    pub fonts: Fonts,
    timelines: Timelines,
    objects: Objects,
    rooms: Rooms,
    dafl: Dafl,
    tpag: Tpag,
    code: Code,
    variables: Variables,
    functions: Functions,
    /// The strings of the game.
    pub strings: Strings,
    textures: Textures,
    audio: Audio,
}

/// A reader that satisfies the requirements for reading a GameData.
pub trait GameDataRead: Read + io::Seek {}
impl<T: Read + io::Seek> GameDataRead for T {}
/// A writer that satisfies the requirements for writing a GameData.
pub trait GameDataWrite: Write + io::Seek {}
impl<T: Write + io::Seek> GameDataWrite for T {}

impl GameData {
    /// Reads a GameData from a reader.
    pub fn from_reader<R: GameDataRead>(reader: &mut R) -> Result<GameData, ReadError> {
        gamedata_io::read(reader)
    }
    /// Reads a GameData from a file.
    pub fn from_file<P: AsRef<path::Path>>(path: &P) -> Result<GameData, ReadError> {
        use std::fs::File;
        use std::io::BufReader;
        let file = try!(File::open(path));
        GameData::from_reader(&mut BufReader::new(file))
    }
    /// Writes self to a writer.
    pub fn write_to_writer<W: GameDataWrite>(&self, writer: &mut W) -> io::Result<()> {
        gamedata_io::write(self, writer)
    }
    /// Writes self to a file.
    pub fn save_to_file<P: AsRef<path::Path>>(&self, path: &P) -> io::Result<()> {
        use std::fs::File;
        use std::io::BufWriter;
        let file = try!(File::create(path));
        self.write_to_writer(&mut BufWriter::new(file))
    }
    /// Returns the window width of the game.
    pub fn window_width(&self) -> u32 {
        self.metadata.window_width
    }
    /// Returns the window height of the game.
    pub fn window_height(&self) -> u32 {
        self.metadata.window_height
    }
    /// Sets the window dimensions of the game.
    pub fn set_window_dimensions(&mut self, width: u32, height: u32) {
        self.metadata.window_width = width;
        self.metadata.window_height = height;
    }
    /// Returns the window title of the game.
    pub fn window_title(&self) -> &str {
        &self.strings.strings[self.metadata.window_title_index]
    }
    /// Sets the window title of the game.
    pub fn set_window_title<S: Into<String>>(&mut self, new: S) {
        self.strings.strings[self.metadata.window_title_index] = new.into();
    }
}

/// Contains various metadata, for example, the window width/height/title.
struct MetaData {
    unk1: u32, // Purpose unknown
    game_id_1_index: usize, // Some kind of game id
    default_index: usize, // Points to "Default"
    unk2: u32,
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
    unk7: u32,
    unk8: u32,
    game_id_2_index: usize, // Some kind of game id, identical to game_id_1
    unk9: u32,
    unk10: u32,
    unk11: u32,
    unk12: u32,
    window_width: u32,
    window_height: u32,
    unk13: u32,
    unk14: u32,
    unk15: u32,
    unk16: u32,
    unk17: u32,
    unk18: u32,
    unk19: u32,
    unk20: u32,
    window_title_index: usize,
    unknown: Vec<u32>,
}

/// Game Maker project Options
struct Options {
    unk1: u32, // Unknown
    unk2: u32, // Unknown
    icon_offset: u32, // Points to texture data (icon?)
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
    unk7: u32,
    unk8: u32,
    unk9: u32,
    unk10: u32,
    unk11: u32,
    unk12: u32,
    unk13: u32,
    unk14: u32,
    unk15: u32,
    constant1_name_index: usize, // Offset of the name of this constant in the string table
    constant2_name_index: usize, // Offset of the name of this constant in the string table
    constant3_name_index: usize, // Offset of the name of this constant in the string table
    constant4_name_index: usize, // Offset of the name of this constant in the string table
    constant5_name_index: usize, // Offset of the name of this constant in the string table
    constant6_name_index: usize, // Offset of the name of this constant in the string table
    constant7_name_index: usize, // Offset of the name of this constant in the string table
    constant8_name_index: usize, // Offset of the name of this constant in the string table
    constant9_name_index: usize, // Offset of the name of this constant in the string table
    constant10_name_index: usize, // Offset of the name of this constant in the string table
    constant11_name_index: usize, // Offset of the name of this constant in the string table
    constant12_name_index: usize, // Offset of the name of this constant in the string table
    constant13_name_index: usize, // Offset of the name of this constant in the string table
    constant14_name_index: usize, // Offset of the name of this constant in the string table
}

/// Purpose unknown.
struct Extn {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker sound.
#[derive(Clone, Copy)]
pub struct Sound {
    /// Index of the name in the string table.
    pub name_index: usize,
    unk1: u32,
    /// Index of the extension in the string table.
    pub ext_index: usize,
    /// Index of the filename in the string table.
    pub filename_index: usize,
    unk2: u32,
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
}

/// A collection of sounds.
pub struct Sounds {
    /// The sounds.
    pub sounds: Vec<Sound>,
}

/// Collection of audio groups. Not present in all games.
struct AudioGroups {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of sprites.
struct Sprites {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of backgrounds.
struct Backgrounds {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of paths.
struct Paths {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker script.
struct Script {
    /// Index of the name of the script in the string table
    pub name_index: usize,
    unknown: u32, // Unknown
}

/// A collection of scripts.
struct Scripts {
    pub scripts: Vec<Script>,
}

/// A collection of shaders.
struct Shaders {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A font.
#[derive(Clone)]
pub struct Font {
    /// Index of the font's resource name in the string table.
    pub name_index: usize,
    /// Index of the font's font name in the string table.
    pub font_name_index: usize,
    /// Point size of the font.
    pub point_size: u32,
    data: Vec<u8>,
}

/// A collection of fonts.
pub struct Fonts {
    /// The fonts.
    pub fonts: Vec<Font>,
    unknown: Vec<u8>, // Unknown trailing data
}

/// A collection of timelines.
struct Timelines {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of objects.
struct Objects {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of rooms.
struct Rooms {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Purpose unknown.
struct Dafl {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Purpose unknown.
struct Tpag {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Something to do with code. Maybe code of scripts?
struct Code {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker variable.
struct Variable {
    /// Index of the name of the variable in the strings section.
    pub name_index: usize,
    unknown: u32, // Purpose unknown. Ranges from 1 to a few thousand.
    code_offset: u32, // Points into the code section
}

/// A collection of variables.
struct Variables {
    pub variables: Vec<Variable>,
}

/// A game maker function.
struct Function {
    /// Index of the name of the function in the strings section.
    pub name_index: usize,
    unknown: u32, // Purpose unknown. Ranges from 1 to a few thousand.
    code_offset: u32, // Points into the code section.
}

/// A collection of functions.
struct Functions {
    pub functions: Vec<Function>,
}

/// A collection of strings.
///
/// All strings are assumed to be valid UTF-8.
pub struct Strings {
    /// The vector holding the strings.
    pub strings: Vec<String>,
}

struct Texture {
    unknown: u32, // Purpose unknown. Always seems to be 1.
    offset: u32, // Offset of data in the texture data
}

/// A collection of textures.
struct Textures {
    pub textures: Vec<Texture>,
    texture_data: Vec<u8>,
}

struct AudioData {
    data: Vec<u8>,
}

/// A collection of audio data.
struct Audio {
    audio: Vec<AudioData>,
    offsets: Vec<u32>, // Audio data is not contiguous, so we need to store relative offsets
    size: u32, // Fuck it
}
<|endoftext|>


<commit_before>#![crate_name = "spread"]
#![comment = "A Rust client library for the Spread toolkit"]
#![crate_type = "lib"]
#![license = "MIT"]

#[deny(non_camel_case_types)]

extern crate encoding;

use encoding::{Encoding, EncodeStrict, DecodeStrict};
use encoding::all::ISO_8859_1;
use std::io::{ConnectionFailed, ConnectionRefused, IoError, IoResult, OtherIoError};
use std::io::net::ip::SocketAddr;
use std::io::net::tcp::TcpStream;
use std::result::Result;
use util::{bytes_to_int, flip_endianness, int_to_bytes, same_endianness};

mod test;
mod util;

pub static DefaultSpreadPort: i16 = 4803;

static MaxPrivateNameLength: uint = 10;
static DefaultAuthName: &'static str  = "NULL";
static MaxAuthNameLength: uint = 30;
static MaxAuthMethodCount: uint = 3;
static MaxGroupNameLength: uint = 32;

// Control message types.
// NOTE: The only currently-implemented service type for messaging is "reliable".
enum ControlServiceType {
    JoinMessage     = 0x00010000,
    LeaveMessage    = 0x00020000,
    KillMessage     = 0x00040000,
    ReliableMessage = 0x00000002
}

static SpreadMajorVersion: u8 = 4;
static SpreadMinorVersion: u8 = 4;
static SpreadPatchVersion: u8 = 0;

// Error codes, as per http://www.spread.org/docs/spread_docs_4/docs/error_codes.html
pub enum SpreadError {
    AcceptSession = 1,
    IllegalSpread = -1,
    CouldNotConnection = -2,
    RejectQuota = -3,
    RejectNOName = -4,
    RejectIllegalName = -5,
    RejectNotUnique = -6,
    RejectVersion = -7,
    ConnectionClosed = -8,
    RejectAuth = -9,
    IllegalSession = -11,
    IllegalService = -12,
    IllegalMessage = -13,
    IllegalGroup = -14,
    BufferTooShort = -15,
    GroupsTooShort = -16,
    MessageTooLong = -17,
    NetErrorOnSession = -18
}

/// A message to be sent or received by a Spread client to/from a group.
pub struct SpreadMessage {
    service_type: u32,
    pub groups: Vec<String>,
    pub sender: String,
    pub data: Vec<u8>,
}

/// Representation of a client connection to a Spread daemon.
pub struct SpreadClient {
    stream: TcpStream,
    pub private_name: String,
    pub groups: Vec<String>,
    receive_membership_messages: bool
}

// Construct a byte vector representation of a connect message for the given
// connection arguments.
fn encode_connect_message(
    private_name: &str,
    receive_membership_messages: bool
) -> Result<Vec<u8>, String> {
    let mut vec: Vec<u8> = Vec::new();

    // Set Spread version.
    vec.push(SpreadMajorVersion);
    vec.push(SpreadMinorVersion);
    vec.push(SpreadPatchVersion);

    // Apply masks for group membership (and priority, which is unimplemented).
    let mask = if receive_membership_messages {
        0x10
    } else {
        0
    };
    vec.push(mask);

    let private_name_buf = try!(ISO_8859_1.encode(private_name, EncodeStrict).map_err(
        |_| format!("Failed to encode private name: {}", private_name)
            ));

    vec.push(private_name.char_len() as u8);
    vec.push_all_move(private_name_buf);
    Ok(vec)
}

/// Establishes a named connection to a Spread daemon running at a given
/// `SocketAddr`.
///
/// *Arguments:*
///
/// - `addr`: The address at which the Spread daemon is running.
/// - `private_name`: A name to use privately to refer to the connection.
/// - `receive_membership_messages`: If true, membership messages will be
///   received by the resultant client.
pub fn connect(
    addr: SocketAddr,
    private_name: &str,
    receive_membership_messages: bool
) -> IoResult<SpreadClient> {
    // Truncate (if necessary) and write `private_name`.
    let truncated_private_name = match private_name {
        too_long if too_long.char_len() > MaxPrivateNameLength =>
            too_long.slice_to(MaxPrivateNameLength),
        just_fine => just_fine
    };

    // Send the initial connect message.
    let connect_message = try!(encode_connect_message(
        truncated_private_name,
        receive_membership_messages
    ).map_err(|error_msg| IoError {
        kind: ConnectionFailed,
        desc: "",
        detail: Some(error_msg)
    }));

    let mut stream = try!(TcpStream::connect(addr.ip.to_string().as_slice(), addr.port));
    try!(stream.write(connect_message.as_slice()));

    // Read the authentication methods.
    let authname_len = try!(stream.read_byte()) as i32;
    if authname_len == -1 {
        return Err(IoError {
            kind: ConnectionFailed,
            desc: "Connection closed during connect attempt to read auth name length",
            detail: None
        });
    } else if authname_len >= 128 {
        return Err(IoError {
            kind: ConnectionRefused,
            desc: "Connection attempt rejected",
            detail: Some(format!("{}", (0xffffff00 | authname_len as u32) as i32))
        });
    }

    // Ignore the list.
    // TODO: Support IP-based auth?
    try!(stream.read_exact(authname_len as uint));

    // Send auth method choice.
    let mut authname_vec: Vec<u8> = match ISO_8859_1.encode(DefaultAuthName, EncodeStrict) {
        Ok(vec) => vec,
        Err(error) => return Err(IoError {
            kind: ConnectionFailed,
            desc: "Failed to encode authname",
            detail: Some(format!("{}", error))
        })
    };

    for _ in range(authname_len as uint, (MaxAuthNameLength * MaxAuthMethodCount + 1)) {
        authname_vec.push(0);
    }
    try!(stream.write(authname_vec.as_slice()));

    // Check for an accept message.
    let accepted: u8 = try!(stream.read_byte());
    if accepted != AcceptSession as u8 {
        return Err(IoError {
            kind: ConnectionFailed,
            desc: "Connection attempt rejected",
            detail: Some(format!("{}", (0xffffff00 | accepted as u32) as i32))
        });
    }

    // Read the version of Spread that the server is running.
    let (major, minor, patch) =
        (try!(stream.read_byte()) as i32, try!(stream.read_byte()) as i32, try!(stream.read_byte()) as i32);

    if major == -1 || minor == -1 || patch == -1 {
        return Err(IoError {
            kind: ConnectionFailed,
            desc: "Invalid version returned from server",
            detail: Some(format!("{}.{}.{}", major, minor, patch))
        });
    }

    let version_sum = (major*10000) + (minor*100) + patch;
    if version_sum < 30100 {
        return Err(IoError {
            kind: ConnectionFailed,
            desc: "Server is running old, unsupported version of Spread",
            detail: Some(format!("{}.{}.{}", major, minor, patch))
        });
    }

    // Read the private group name.
    let group_name_len = try!(stream.read_byte()) as i32;
    if group_name_len == -1 {
        return Err(IoError {
            kind: ConnectionFailed,
            desc: "Connection closed during connect attempt to read group name length",
            detail: None
        });
    }
    let group_name_buf = try!(stream.read_exact(group_name_len as uint));
    let private_group_name = match String::from_utf8(group_name_buf) {
        Ok(group_name) => group_name,
        Err(error) => return Err(IoError {
            kind: ConnectionFailed,
            desc: "Server sent invalid group name",
            detail: Some(format!("{}", error))
        })
    };

    Ok(SpreadClient {
        stream: stream,
        private_name: private_group_name,
        groups: Vec::new(),
        receive_membership_messages: receive_membership_messages
    })
}

impl SpreadClient {
    // Encode a service message for dispatch to a Spread daemon.
    fn encode_message(
        service_type: u32,
        private_name: &str,
        groups: &[&str],
        data: &[u8]
    ) -> Result<Vec<u8>, String> {
        let mut vec: Vec<u8> = Vec::new();
        vec.push_all_move(int_to_bytes(service_type));

        let private_name_buf = try!(ISO_8859_1.encode(private_name, EncodeStrict).map_err(
            |_| format!("Failed to encode private name: {}", private_name)
        ));
        vec.push_all_move(private_name_buf);
        for _ in range(private_name.len(), (MaxGroupNameLength)) {
            vec.push(0);
        }

        vec.push_all_move(int_to_bytes(groups.len() as u32));
        vec.push_all_move(int_to_bytes(0));
        vec.push_all_move(int_to_bytes(data.len() as u32));

        // Encode and push each group name, converting any encoding errors
        // to error message strings.
        for group in groups.iter() {
            let group_buf = try!(ISO_8859_1.encode(*group, EncodeStrict).map_err(
                |_| format!("Failed to encode group name: {}", group)
            ));
            vec.push_all_move(group_buf);
            for _ in range(group.len(), (MaxGroupNameLength)) {
                vec.push(0);
            }
        }

        vec.push_all(data);
        Ok(vec)
    }

    /// Disconnects the client from the Spread daemon.
    // TODO: Prevent further usage of client?
    pub fn disconnect(&mut self) -> IoResult<()> {
        let name_slice = self.private_name.as_slice();
        let kill_message = try!(SpreadClient::encode_message(
            KillMessage as u32,
            name_slice,
            [name_slice],
            []
        ).map_err(|error_msg| IoError {
            kind: OtherIoError,
            desc: "Disconnection failed",
            detail: Some(error_msg)
        }));

        self.stream.write(kill_message.as_slice())
    }

    /// Join a named Spread group.
    ///
    /// All messages sent to the group will be received by the client until it
    /// has left the group.
    pub fn join(&mut self, group_name: &str) -> IoResult<()> {
        let join_message = try!(SpreadClient::encode_message(
            JoinMessage as u32,
            self.private_name.as_slice(),
            [group_name],
            []
        ).map_err(|error_msg| IoError {
            kind: OtherIoError,
            desc: "Disconnection failed",
            detail: Some(error_msg)
        }));

        try!(self.stream.write(join_message.as_slice()));
        self.groups.push(group_name.to_string());
        Ok(())
    }

    /// Leave a named Spread group.
    pub fn leave(&mut self, group_name: &str) -> IoResult<()> {
        let leave_message = try!(SpreadClient::encode_message(
            LeaveMessage as u32,
            self.private_name.as_slice(),
            [group_name],
            []
        ).map_err(|error_msg| IoError {
            kind: OtherIoError,
            desc: "Disconnection failed",
            detail: Some(error_msg)
        }));

        try!(self.stream.write(leave_message.as_slice()));
        self.groups.push(group_name.to_string());
        Ok(())
    }

    /// Send a message to a set of named groups.
    pub fn multicast(
        &mut self,
        groups: &[&str],
        data: &[u8]
    ) -> IoResult<()> {
        let message = try!(SpreadClient::encode_message(
            ReliableMessage as u32,
            self.private_name.as_slice(),
            groups,
            data
        ).map_err(|error_msg| IoError {
            kind: OtherIoError,
            desc: "Disconnection failed",
            detail: Some(error_msg)
        }));

        self.stream.write(message.as_slice())
    }

    /// Receive the next available message. If there are no messages available,
    /// the call will block until either a message is received or a timeout
    /// expires.
    pub fn receive(&mut self) -> IoResult<SpreadMessage> {
        // Header format (sizes in bytes):
        //   svc_type:   4
        //   sender:    32
        //   num_groups: 4
        //   hint:       4
        //   data_len:   4
        let header_vec = try!(self.stream.read_exact(MaxGroupNameLength + 16));
        let is_correct_endianness = same_endianness(bytes_to_int(header_vec.slice(0, 4)));

        let svc_type = match (is_correct_endianness, bytes_to_int(header_vec.slice(0, 4))) {
            (true, correct) => correct,
            (false, incorrect) => flip_endianness(incorrect)
        };

        let sender = try!(
            ISO_8859_1.decode(header_vec.slice(4, 36), DecodeStrict).map_err(|error| IoError {
                kind: OtherIoError,
                desc: "Decoding sender name failed",
                detail: Some(String::from_str(error.as_slice()))
            })
        );

        let num_groups = match (is_correct_endianness, bytes_to_int(header_vec.slice(36, 40))) {
            (true, correct) => correct,
            (false, incorrect) => flip_endianness(incorrect)
        };
        let data_len = match (is_correct_endianness, bytes_to_int(header_vec.slice(44, 48))) {
            (true, correct) => correct,
            (false, incorrect) => flip_endianness(incorrect)
        };

        // Groups format (sizes in bytes):
        //   groups: num_groups
        let groups_vec =
            try!(self.stream.read_exact(MaxGroupNameLength * num_groups as uint));
        let mut groups = Vec::new();

        for n in range(0, num_groups) {
            let i: uint = n as uint * MaxGroupNameLength;
            let group = try!(
                ISO_8859_1.decode(groups_vec.slice(i, i + MaxGroupNameLength), DecodeStrict)
                    .map_err(|error| IoError {
                        kind: OtherIoError,
                        desc: "Decoding group name failed",
                        detail: Some(String::from_str(error.as_slice()))
                    }));
            groups.push(group);
        }

        // Data format (sizes in bytes):
        //   data: data_len
        let data_vec = try!(self.stream.read_exact(data_len as uint));

        Ok(SpreadMessage {
            service_type: svc_type as u32,
            groups: groups,
            sender: sender,
            data: data_vec
        })
    }
}
<commit_msg>Add debug logging statements<commit_after>#![crate_name = "spread"]
#![comment = "A Rust client library for the Spread toolkit"]
#![crate_type = "lib"]
#![license = "MIT"]

#![feature(phase)]
#[deny(non_camel_case_types)]

extern crate encoding;
#[phase(plugin, link)] extern crate log;

use encoding::{Encoding, EncodeStrict, DecodeStrict};
use encoding::all::ISO_8859_1;
use std::io::{ConnectionFailed, ConnectionRefused, IoError, IoResult, OtherIoError};
use std::io::net::ip::SocketAddr;
use std::io::net::tcp::TcpStream;
use std::result::Result;
use util::{bytes_to_int, flip_endianness, int_to_bytes, same_endianness};

mod test;
mod util;

pub static DefaultSpreadPort: i16 = 4803;

static MaxPrivateNameLength: uint = 10;
static DefaultAuthName: &'static str  = "NULL";
static MaxAuthNameLength: uint = 30;
static MaxAuthMethodCount: uint = 3;
static MaxGroupNameLength: uint = 32;

// Control message types.
// NOTE: The only currently-implemented service type for messaging is "reliable".
enum ControlServiceType {
    JoinMessage     = 0x00010000,
    LeaveMessage    = 0x00020000,
    KillMessage     = 0x00040000,
    ReliableMessage = 0x00000002
}

static SpreadMajorVersion: u8 = 4;
static SpreadMinorVersion: u8 = 4;
static SpreadPatchVersion: u8 = 0;

// Error codes, as per http://www.spread.org/docs/spread_docs_4/docs/error_codes.html
pub enum SpreadError {
    AcceptSession = 1,
    IllegalSpread = -1,
    CouldNotConnection = -2,
    RejectQuota = -3,
    RejectNOName = -4,
    RejectIllegalName = -5,
    RejectNotUnique = -6,
    RejectVersion = -7,
    ConnectionClosed = -8,
    RejectAuth = -9,
    IllegalSession = -11,
    IllegalService = -12,
    IllegalMessage = -13,
    IllegalGroup = -14,
    BufferTooShort = -15,
    GroupsTooShort = -16,
    MessageTooLong = -17,
    NetErrorOnSession = -18
}

/// A message to be sent or received by a Spread client to/from a group.
pub struct SpreadMessage {
    service_type: u32,
    pub groups: Vec<String>,
    pub sender: String,
    pub data: Vec<u8>,
}

/// Representation of a client connection to a Spread daemon.
pub struct SpreadClient {
    stream: TcpStream,
    pub private_name: String,
    pub groups: Vec<String>,
    receive_membership_messages: bool
}

// Construct a byte vector representation of a connect message for the given
// connection arguments.
fn encode_connect_message(
    private_name: &str,
    receive_membership_messages: bool
) -> Result<Vec<u8>, String> {
    let mut vec: Vec<u8> = Vec::new();

    // Set Spread version.
    vec.push(SpreadMajorVersion);
    vec.push(SpreadMinorVersion);
    vec.push(SpreadPatchVersion);

    // Apply masks for group membership (and priority, which is unimplemented).
    let mask = if receive_membership_messages {
        0x10
    } else {
        0
    };
    vec.push(mask);

    let private_name_buf = try!(ISO_8859_1.encode(private_name, EncodeStrict).map_err(
        |_| format!("Failed to encode private name: {}", private_name)
            ));

    vec.push(private_name.char_len() as u8);
    vec.push_all_move(private_name_buf);
    Ok(vec)
}

/// Establishes a named connection to a Spread daemon running at a given
/// `SocketAddr`.
///
/// *Arguments:*
///
/// - `addr`: The address at which the Spread daemon is running.
/// - `private_name`: A name to use privately to refer to the connection.
/// - `receive_membership_messages`: If true, membership messages will be
///   received by the resultant client.
pub fn connect(
    addr: SocketAddr,
    private_name: &str,
    receive_membership_messages: bool
) -> IoResult<SpreadClient> {
    // Truncate (if necessary) and write `private_name`.
    let truncated_private_name = match private_name {
        too_long if too_long.char_len() > MaxPrivateNameLength =>
            too_long.slice_to(MaxPrivateNameLength),
        just_fine => just_fine
    };

    // Send the initial connect message.
    let connect_message = try!(encode_connect_message(
        truncated_private_name,
        receive_membership_messages
    ).map_err(|error_msg| IoError {
        kind: ConnectionFailed,
        desc: "",
        detail: Some(error_msg)
    }));

    let mut stream = try!(TcpStream::connect(addr.ip.to_string().as_slice(), addr.port));
    debug!("Sending connect message to {}", addr);
    try!(stream.write(connect_message.as_slice()));

    // Read the authentication methods.
    let authname_len = try!(stream.read_byte()) as i32;
    if authname_len == -1 {
        return Err(IoError {
            kind: ConnectionFailed,
            desc: "Connection closed during connect attempt to read auth name length",
            detail: None
        });
    } else if authname_len >= 128 {
        return Err(IoError {
            kind: ConnectionRefused,
            desc: "Connection attempt rejected",
            detail: Some(format!("{}", (0xffffff00 | authname_len as u32) as i32))
        });
    }

    // Ignore the list.
    // TODO: Support IP-based auth?
    let authname_vec = try!(stream.read_exact(authname_len as uint));
    let authname = try!(ISO_8859_1.decode(authname_vec.as_slice(), DecodeStrict).map_err(|error| IoError {
        kind: OtherIoError,
        desc: "Failed to decode received authname",
        detail: Some(String::from_str(error.as_slice()))
    }));
    debug!("Received authentication method choice(s): {}", authname);

    // Send auth method choice.
    let mut authname_vec: Vec<u8> = match ISO_8859_1.encode(DefaultAuthName, EncodeStrict) {
        Ok(vec) => vec,
        Err(error) => return Err(IoError {
            kind: ConnectionFailed,
            desc: "Failed to encode authname",
            detail: Some(format!("{}", error))
        })
    };

    for _ in range(authname_len as uint, (MaxAuthNameLength * MaxAuthMethodCount + 1)) {
        authname_vec.push(0);
    }

    debug!("Sending authentication method choice of {}", DefaultAuthName);
    try!(stream.write(authname_vec.as_slice()));

    // Check for an accept message.
    let accepted: u8 = try!(stream.read_byte());
    if accepted != AcceptSession as u8 {
        return Err(IoError {
            kind: ConnectionFailed,
            desc: "Connection attempt rejected",
            detail: Some(format!("{}", (0xffffff00 | accepted as u32) as i32))
        });
    }

    debug!("Received session acceptance message from daemon");

    // Read the version of Spread that the server is running.
    let (major, minor, patch) =
        (try!(stream.read_byte()) as i32, try!(stream.read_byte()) as i32, try!(stream.read_byte()) as i32);

    debug!(
        "Received version message: daemon running Spread version {}.{}.{}",
        major, minor, patch
    );

    if major == -1 || minor == -1 || patch == -1 {
        return Err(IoError {
            kind: ConnectionFailed,
            desc: "Invalid version returned from server",
            detail: Some(format!("{}.{}.{}", major, minor, patch))
        });
    }

    let version_sum = (major*10000) + (minor*100) + patch;
    if version_sum < 30100 {
        return Err(IoError {
            kind: ConnectionFailed,
            desc: "Server is running old, unsupported version of Spread",
            detail: Some(format!("{}.{}.{}", major, minor, patch))
        });
    }

    // Read the private group name.
    let group_name_len = try!(stream.read_byte()) as i32;
    if group_name_len == -1 {
        return Err(IoError {
            kind: ConnectionFailed,
            desc: "Connection closed during connect attempt to read group name length",
            detail: None
        });
    }
    let group_name_buf = try!(stream.read_exact(group_name_len as uint));
    let private_group_name = match String::from_utf8(group_name_buf) {
        Ok(group_name) => group_name,
        Err(error) => return Err(IoError {
            kind: ConnectionFailed,
            desc: "Server sent invalid group name",
            detail: Some(format!("{}", error))
        })
    };

    debug!("Received private name assignment from daemon: {}", private_group_name);
    debug!("Client connected to daemon at {}", addr);

    Ok(SpreadClient {
        stream: stream,
        private_name: private_group_name,
        groups: Vec::new(),
        receive_membership_messages: receive_membership_messages
    })
}

impl SpreadClient {
    // Encode a service message for dispatch to a Spread daemon.
    fn encode_message(
        service_type: u32,
        private_name: &str,
        groups: &[&str],
        data: &[u8]
    ) -> Result<Vec<u8>, String> {
        let mut vec: Vec<u8> = Vec::new();
        vec.push_all_move(int_to_bytes(service_type));

        let private_name_buf = try!(ISO_8859_1.encode(private_name, EncodeStrict).map_err(
            |_| format!("Failed to encode private name: {}", private_name)
        ));
        vec.push_all_move(private_name_buf);
        for _ in range(private_name.len(), (MaxGroupNameLength)) {
            vec.push(0);
        }

        vec.push_all_move(int_to_bytes(groups.len() as u32));
        vec.push_all_move(int_to_bytes(0));
        vec.push_all_move(int_to_bytes(data.len() as u32));

        // Encode and push each group name, converting any encoding errors
        // to error message strings.
        for group in groups.iter() {
            let group_buf = try!(ISO_8859_1.encode(*group, EncodeStrict).map_err(
                |_| format!("Failed to encode group name: {}", group)
            ));
            vec.push_all_move(group_buf);
            for _ in range(group.len(), (MaxGroupNameLength)) {
                vec.push(0);
            }
        }

        vec.push_all(data);
        Ok(vec)
    }

    /// Disconnects the client from the Spread daemon.
    // TODO: Prevent further usage of client?
    pub fn disconnect(&mut self) -> IoResult<()> {
        let name_slice = self.private_name.as_slice();
        let kill_message = try!(SpreadClient::encode_message(
            KillMessage as u32,
            name_slice,
            [name_slice],
            []
        ).map_err(|error_msg| IoError {
            kind: OtherIoError,
            desc: "Disconnection failed",
            detail: Some(error_msg)
        }));

        debug!("Disconnecting from daemon at {}", try!(self.stream.peer_name()));
        self.stream.write(kill_message.as_slice())
    }

    /// Join a named Spread group.
    ///
    /// All messages sent to the group will be received by the client until it
    /// has left the group.
    pub fn join(&mut self, group_name: &str) -> IoResult<()> {
        let join_message = try!(SpreadClient::encode_message(
            JoinMessage as u32,
            self.private_name.as_slice(),
            [group_name],
            []
        ).map_err(|error_msg| IoError {
            kind: OtherIoError,
            desc: "Disconnection failed",
            detail: Some(error_msg)
        }));

        debug!("Client \"{}\" joining group \"{}\"", self.private_name, group_name);
        try!(self.stream.write(join_message.as_slice()));
        self.groups.push(group_name.to_string());
        Ok(())
    }

    /// Leave a named Spread group.
    pub fn leave(&mut self, group_name: &str) -> IoResult<()> {
        let leave_message = try!(SpreadClient::encode_message(
            LeaveMessage as u32,
            self.private_name.as_slice(),
            [group_name],
            []
        ).map_err(|error_msg| IoError {
            kind: OtherIoError,
            desc: "Disconnection failed",
            detail: Some(error_msg)
        }));

        debug!("Client \"{}\" leaving group \"{}\"", self.private_name, group_name);
        try!(self.stream.write(leave_message.as_slice()));
        self.groups.push(group_name.to_string());
        Ok(())
    }

    /// Send a message to a set of named groups.
    pub fn multicast(
        &mut self,
        groups: &[&str],
        data: &[u8]
    ) -> IoResult<()> {
        let message = try!(SpreadClient::encode_message(
            ReliableMessage as u32,
            self.private_name.as_slice(),
            groups,
            data
        ).map_err(|error_msg| IoError {
            kind: OtherIoError,
            desc: "Disconnection failed",
            detail: Some(error_msg)
        }));

        debug!("Client \"{}\" multicasting {} bytes to group(s) {}",
               self.private_name, data.len(), groups);
        self.stream.write(message.as_slice())
    }

    /// Receive the next available message. If there are no messages available,
    /// the call will block until either a message is received or a timeout
    /// expires.
    pub fn receive(&mut self) -> IoResult<SpreadMessage> {
        // Header format (sizes in bytes):
        //   svc_type:   4
        //   sender:    32
        //   num_groups: 4
        //   hint:       4
        //   data_len:   4
        let header_vec = try!(self.stream.read_exact(MaxGroupNameLength + 16));
        let is_correct_endianness = same_endianness(bytes_to_int(header_vec.slice(0, 4)));

        let svc_type = match (is_correct_endianness, bytes_to_int(header_vec.slice(0, 4))) {
            (true, correct) => correct,
            (false, incorrect) => flip_endianness(incorrect)
        };

        let sender = try!(
            ISO_8859_1.decode(header_vec.slice(4, 36), DecodeStrict).map_err(|error| IoError {
                kind: OtherIoError,
                desc: "Failed to decode sender name",
                detail: Some(String::from_str(error.as_slice()))
            })
        );

        let num_groups = match (is_correct_endianness, bytes_to_int(header_vec.slice(36, 40))) {
            (true, correct) => correct,
            (false, incorrect) => flip_endianness(incorrect)
        };
        let data_len = match (is_correct_endianness, bytes_to_int(header_vec.slice(44, 48))) {
            (true, correct) => correct,
            (false, incorrect) => flip_endianness(incorrect)
        };

        // Groups format (sizes in bytes):
        //   groups: num_groups
        let groups_vec =
            try!(self.stream.read_exact(MaxGroupNameLength * num_groups as uint));
        let mut groups = Vec::new();

        for n in range(0, num_groups) {
            let i: uint = n as uint * MaxGroupNameLength;
            let group = try!(
                ISO_8859_1.decode(groups_vec.slice(i, i + MaxGroupNameLength), DecodeStrict)
                    .map_err(|error| IoError {
                        kind: OtherIoError,
                        desc: "Failed to decode group name",
                        detail: Some(String::from_str(error.as_slice()))
                    }));
            groups.push(group);
        }

        // Data format (sizes in bytes):
        //   data: data_len
        let data_vec = try!(self.stream.read_exact(data_len as uint));

        debug!("Received {} bytes from \"{}\" sent to group(s) {}",
               data_len, sender, groups);

        Ok(SpreadMessage {
            service_type: svc_type as u32,
            groups: groups,
            sender: sender,
            data: data_vec
        })
    }
}
<|endoftext|>


<commit_before>pub mod connection;
pub mod error;
pub mod server;
pub mod target;
<commit_msg>lib: explicitly export symbols<commit_after>mod connection;
mod error;
mod server;
mod target;

pub use connection::DBusConnection as DBusConnection;
pub use error::DBusError as DBusError;
pub use server::DBusServer as DBusServer;
pub use target::DBusTarget as DBusTarget;
<|endoftext|>


<commit_before>//! A simple `io::stdout` and `io::stderr` writing `Logger` implementation from the
//! `log` crate, using the `ansi_term` crate for colors and configured at runtime,
//! or at compile time with simple function calls. Designed for simple CLIs.
//!
//! This library only comes with 3 public ways to initialize the global logger.
//! Ensure you call one of these exactly once early in your rust program as shown
//! in one of the examples below.
//!
//! ## Example
//! The standard example with `clap` as the arg parser.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate clap;
//! extern crate loggerv;
//!
//! use clap::{Arg, App};
//!
//! fn main() {
//!     let args = App::new("app")
//!                    .arg(Arg::with_name("v")
//!                             .short("v")
//!                             .multiple(true)
//!                             .help("Sets the level of verbosity"))
//!                    .get_matches();
//!
//!     loggerv::init_with_verbosity(args.occurrences_of("v")).unwrap();
//!
//!     error!("this is always printed");
//!     warn!("this too, and it's printed to stderr");
//!     info!("this is optional");  // for ./app -v or higher
//!     debug!("this is optional"); // for ./app -vv or higher
//!     trace!("this is optional"); // for ./app -vvv
//! }
//! ```
//!
//! But obviously use whatever argument parsing methods you prefer.
//!
//! ## Example
//! For a compile time switch, all you really need is `log` (for the macros)
//! and `loggerv` for how to print what's being sent to the macros.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! use log::LogLevel;
//!
//! fn main() {
//!     loggerv::init_with_level(LogLevel::Info).unwrap();
//!     debug!("this is a debug {}", "message");
//!     error!("this is printed by default");
//! }
//! ```
//!
//! # Example
//! If you don't really care at all you could just use the plain `init_quiet` function
//! to only show warnings and errors:
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! fn main() {
//!     loggerv::init_quiet().unwrap();
//!     info!("hidden");
//!     error!("this is printed by default");
//! }
//! ```
//!
//!
//! See the documentation for the log crate for more information about its API.
//!

extern crate log;
extern crate ansi_term;

use log::{Log, LogLevel, LogMetadata, LogRecord, SetLoggerError};
use std::io::{self, Write};
use ansi_term::Colour;

struct VLogger {
    log_level: LogLevel,
}

fn level_style(l: LogLevel) -> Colour {
    match l {
        LogLevel::Error => Colour::Fixed(9), // bright red
        LogLevel::Warn => Colour::Fixed(11), // bright yellow
        LogLevel::Info => Colour::Fixed(10), // bright green
        LogLevel::Debug => Colour::Fixed(7), // light grey
        LogLevel::Trace => Colour::Fixed(8), // grey
    }
}

impl Log for VLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.log_level
    }

    #[allow(unused_must_use)]
    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let msg = format!("{}: {}",
                              level_style(record.level()).paint(record.location().module_path()),
                              record.args());
            if record.level() <= LogLevel::Warn {
                writeln!(&mut io::stderr(), "{}", msg);
            } else {
                println!("{}", msg);
            }
        }
    }
}

/// Initialize loggerv with a maximal log level.
///
/// See the main loggerv documentation page for an example.
pub fn init_with_level(log_level: LogLevel) -> Result<(), SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(log_level.to_log_level_filter());
        Box::new(VLogger { log_level: log_level })
    })
}

/// Initialize loggerv with a verbosity level.
///
/// Intended to be used with an arg parser counting the amount of -v flags.
/// See the main loggerv documentation page for an example.
pub fn init_with_verbosity(verbosity: u64) -> Result<(), SetLoggerError> {
    init_with_level(match verbosity {
        0 => LogLevel::Warn,  // default
        1 => LogLevel::Info,  // -v
        2 => LogLevel::Debug, // -vv
        _ => LogLevel::Trace, // -vvv and above
    })
}

/// Initializes loggerv with only warnings and errors.
///
/// See the main loggerv documentation page for an example.
pub fn init_quiet() -> Result<(), SetLoggerError> {
    init_with_level(LogLevel::Warn)
}

#[cfg(test)]
mod tests {
    use init_with_verbosity;

    #[test]
    fn init_and_macros() {
        let l = init_with_verbosity(3);
        assert_eq!(l.is_ok(), true);
        //error!("error log");
        //warn!("warn log");
        //info!("info log");
        //debug!("debug log");
        //trace!("trace log");
    }
}
<commit_msg>ignoe unused result at the use site explicitly<commit_after>//! A simple `io::stdout` and `io::stderr` writing `Logger` implementation from the
//! `log` crate, using the `ansi_term` crate for colors and configured at runtime,
//! or at compile time with simple function calls. Designed for simple CLIs.
//!
//! This library only comes with 3 public ways to initialize the global logger.
//! Ensure you call one of these exactly once early in your rust program as shown
//! in one of the examples below.
//!
//! ## Example
//! The standard example with `clap` as the arg parser.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate clap;
//! extern crate loggerv;
//!
//! use clap::{Arg, App};
//!
//! fn main() {
//!     let args = App::new("app")
//!                    .arg(Arg::with_name("v")
//!                             .short("v")
//!                             .multiple(true)
//!                             .help("Sets the level of verbosity"))
//!                    .get_matches();
//!
//!     loggerv::init_with_verbosity(args.occurrences_of("v")).unwrap();
//!
//!     error!("this is always printed");
//!     warn!("this too, and it's printed to stderr");
//!     info!("this is optional");  // for ./app -v or higher
//!     debug!("this is optional"); // for ./app -vv or higher
//!     trace!("this is optional"); // for ./app -vvv
//! }
//! ```
//!
//! But obviously use whatever argument parsing methods you prefer.
//!
//! ## Example
//! For a compile time switch, all you really need is `log` (for the macros)
//! and `loggerv` for how to print what's being sent to the macros.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! use log::LogLevel;
//!
//! fn main() {
//!     loggerv::init_with_level(LogLevel::Info).unwrap();
//!     debug!("this is a debug {}", "message");
//!     error!("this is printed by default");
//! }
//! ```
//!
//! # Example
//! If you don't really care at all you could just use the plain `init_quiet` function
//! to only show warnings and errors:
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! fn main() {
//!     loggerv::init_quiet().unwrap();
//!     info!("hidden");
//!     error!("this is printed by default");
//! }
//! ```
//!
//!
//! See the documentation for the log crate for more information about its API.
//!

extern crate log;
extern crate ansi_term;

use log::{Log, LogLevel, LogMetadata, LogRecord, SetLoggerError};
use std::io::{self, Write};
use ansi_term::Colour;

struct VLogger {
    log_level: LogLevel,
}

fn level_style(l: LogLevel) -> Colour {
    match l {
        LogLevel::Error => Colour::Fixed(9), // bright red
        LogLevel::Warn => Colour::Fixed(11), // bright yellow
        LogLevel::Info => Colour::Fixed(10), // bright green
        LogLevel::Debug => Colour::Fixed(7), // light grey
        LogLevel::Trace => Colour::Fixed(8), // grey
    }
}

impl Log for VLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.log_level
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let msg = format!("{}: {}",
                              level_style(record.level()).paint(record.location().module_path()),
                              record.args());
            if record.level() <= LogLevel::Warn {
                let _ = writeln!(&mut io::stderr(), "{}", msg);
            } else {
                println!("{}", msg);
            }
        }
    }
}

/// Initialize loggerv with a maximal log level.
///
/// See the main loggerv documentation page for an example.
pub fn init_with_level(log_level: LogLevel) -> Result<(), SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(log_level.to_log_level_filter());
        Box::new(VLogger { log_level: log_level })
    })
}

/// Initialize loggerv with a verbosity level.
///
/// Intended to be used with an arg parser counting the amount of -v flags.
/// See the main loggerv documentation page for an example.
pub fn init_with_verbosity(verbosity: u64) -> Result<(), SetLoggerError> {
    init_with_level(match verbosity {
        0 => LogLevel::Warn,  // default
        1 => LogLevel::Info,  // -v
        2 => LogLevel::Debug, // -vv
        _ => LogLevel::Trace, // -vvv and above
    })
}

/// Initializes loggerv with only warnings and errors.
///
/// See the main loggerv documentation page for an example.
pub fn init_quiet() -> Result<(), SetLoggerError> {
    init_with_level(LogLevel::Warn)
}

#[cfg(test)]
mod tests {
    use init_with_verbosity;

    #[test]
    fn init_and_macros() {
        let l = init_with_verbosity(3);
        assert_eq!(l.is_ok(), true);
        //error!("error log");
        //warn!("warn log");
        //info!("info log");
        //debug!("debug log");
        //trace!("trace log");
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

use std::str;

pub mod terminal {
    pub mod pn;
    pub mod literal;
    pub mod primitive;
}
use terminal::pn::pn_local_esc;
use terminal::primitive::percent;

/* [169s] PLX */
named!(pub plx<&str, &str>, alt!(percent | pn_local_esc));

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

    #[test]
    fn plx_test() {
        assert_eq!(plx("%2Arest"), IResult::Done("rest", "%2A"));
        assert_eq!(plx("\\.rest"), IResult::Done("rest", "\\."));
    }
}
<commit_msg>Add Plx enum<commit_after>#[macro_use]
extern crate nom;

use std::str;

pub mod terminal {
    pub mod pn;
    pub mod literal;
    pub mod primitive;
}
use terminal::pn::pn_local_esc;
use terminal::primitive::percent;

#[derive(PartialEq, Debug)]
pub enum Plx<'a> {
    Percent(&'a str),
    PnLocalEsc(&'a str),
}
/* [169s] PLX */
named!(pub plx<&str, Plx>, alt!(
    map!(percent     , Plx::Percent   ) |
    map!(pn_local_esc, Plx::PnLocalEsc)
));

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

    #[test]
    fn plx_test() {
        assert_eq!(plx("%2Arest"), IResult::Done("rest", Plx::Percent("%2A")));
        assert_eq!(plx("\\.rest"), IResult::Done("rest", Plx::PnLocalEsc("\\.")));
    }
}
<|endoftext|>


<commit_before>#![feature(plugin, core, collections, str_char, convert)]

#![plugin(regex_macros)]

//! # Handlebars
//! Handlebars is a modern and extensible templating solution originally created in the JavaScript world. It's used by many popular frameworks like [Ember.js](http://emberjs.com) and Chaplin. It's also ported to some other platforms such as [Java](https://github.com/jknack/handlebars.java).
//!
//! And this is handlebars Rust implementation, designed for server-side page generation. It's a general-purpose library so you use it for any kind of text generation.
//!
//! ## Handlebars spec
//!
//! ### Base
//!
//! You can go to [Handlebars.js](http://handlebarsjs.com/) website for its syntax. This implementation should be compatible with most parts of the spec, except:
//!
//! * raw helper syntax `{{{raw-helper}}}...{{{/raw-helper}}}` is implemented as block helper raw.
//! * configurable logging (hard-coded to rust native logging, with fixed level `INFO`)
//!
//! ### Extensions
//!
//! We have template reuse facilities supported via built-in helpers `>`, `partial` and `block`.
//!
//! There are two ways to reuse a template:
//!
//! * include (using `>`)
//! * inheritance (using `>` together with `block` and `partial`)
//!
//! Consult [Handlebar.java document about template inheritance](http://jknack.github.io/handlebars.java/reuse.html).
//!
//! ## Usage
//!
//! ### Template Creation and Registration
//!
//! Templates are created from String and registered to `Handlebars` with a name.
//!
//! ```
//!
//! extern crate handlebars;
//!
//! use handlebars::Handlebars;
//!
//! fn main() {
//!   let mut handlebars = Handlebars::new();
//!   let source = "hello {{world}}";
//!
//!   //compile returns an Option, we use unwrap() to deref it directly here
//!   handlebars.register_template_string("helloworld", source.to_string())
//!           .ok().expect("template created");
//! }
//! ```
//!
//! ### Rendering Something
//!
//! I should say that rendering is a little tricky. Since handlebars is originally a JavaScript templating framework. It supports dynamic features like duck-typing, truthy/falsy values. But for a static language like Rust, this is a little difficult. As a solution, I'm using the `serialize::json::Json` internally for data rendering, which seems good by far.
//!
//! That means, if you want to render something, you have to ensure that it implements the `serialize::json::ToJson` trait. Luckily, most built-in types already have trait. However, if you want to render your custom struct, you need to implement this trait manually. (Rust has a deriving facility, but it's just for selected types. Maybe I will add some syntax extensions or macros to simplify this process.)
//!
//! ```
//!
//! extern crate rustc_serialize as serialize;
//! extern crate handlebars;
//!
//! use serialize::json::{Json, ToJson};
//! use std::collections::BTreeMap;
//!
//! use handlebars::Handlebars;
//!
//! struct Person {
//!   name: String,
//!   age: i16,
//! }
//!
//! impl ToJson for Person {
//!   fn to_json(&self) -> Json {
//!     let mut m = BTreeMap::new();
//!     m.insert("name".to_string(), self.name.to_json());
//!     m.insert("age".to_string(), self.age.to_json());
//!     Json::Object(m)
//!   }
//! }
//!
//!
//! fn main() {
//!   let source = "hello {{world}}";
//!
//!   let mut handlebars = Handlebars::new();
//!   handlebars.register_template_string("helloworld", source.to_string())
//!           .ok().expect("template creation failed");
//!
//!   let mut data = Person {
//!       name: "Ning Sun".to_string(),
//!       age: 27
//!   };
//!   let result = handlebars.render("helloworld", &data);
//! }
//! ```
//!
//! ### Custom Helper
//!
//! Handlebars is nothing without helpers. You can also create your own helpers with rust. Helpers in handlebars-rust are custom struct implements the `HelperDef` trait, concretely, the `call` function. For your convenience, most of stateless helpers can be implemented as bare functions.
//!
//! ```
//!
//! extern crate handlebars;
//!
//! use handlebars::{Handlebars, HelperDef, RenderError, RenderContext, Helper, Context};
//!
//! // implement by a structure impls HelperDef
//! #[derive(Copy)]
//! struct SimpleHelper;
//!
//! impl HelperDef for SimpleHelper {
//!   fn call(&self, c: &Context, h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<String, RenderError> {
//!     let param = h.params().get(0).unwrap();
//!
//!     // get value from context data
//!     // rc.get_path() is current json parent path, you should always use it like this
//!     // param is the key of value you want to display
//!     let value = c.navigate(rc.get_path(), param);
//!     Ok(format!("My helper dumps: {} ", value))
//!   }
//! }
//!
//! // implement via bare function
//! fn another_simple_helper (c: &Context, h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<String, RenderError> {
//!     let param = h.params().get(0).unwrap();
//!
//!     // get value from context data
//!     // rc.get_path() is current json parent path, you should always use it like this
//!     // param is the key of value you want to display
//!     let value = c.navigate(rc.get_path(), param);
//!     Ok(format!("My second helper dumps: {} ", value))
//! }
//!
//!
//! fn main() {
//!   let mut handlebars = Handlebars::new();
//!   handlebars.register_helper("simple-helper", Box::new(SimpleHelper));
//!   handlebars.register_helper("another-simple-helper", Box::new(another_simple_helper));
//!
//!   //...
//! }
//! ```
//!
//! #### Arguments of HelpDef
//!
//! You can get data from the `Helper` argument about the template information:
//!
//! * `name()` for the helper name. This is known to you for most situation but if you are defining `helperMissing` or `blockHelperMissing`, this is important.
//! * `params()` is a vector of String as params in helper, like `{{#somehelper param1 param2 param3}}`.
//! * `hash()` is a map of String key and Json value, defined in helper as `{{@somehelper a=1 b="2" c=true}}`.
//! * `template()` gives you the nested template of block helper.
//! * `inverse()` gives you the inversed template of it, inversed template is the template behind `{{else}}`.
//!
//! You can learn more about helpers by looking into source code of built-in helpers.
//!
//! #### Built-in Helpers
//!
//! * `{{#raw}} ... {{/raw}}` escape handlebars expression within the block
//! * `{{#if ...}} ... {{else}} ... {{/if}}` if-else block
//! * `{{#unless ...}} ... {{else}} .. {{/unless}}` if-not-else block
//! * `{{#each ...}} ... {{/each}}` iterates over an array or object. Handlebar-rust doesn't support mustach iteration syntax so use this instead.
//! * `{{#with ...}} ... {{/with}}` change current context. Similar to {{#each}}, used for replace corresponding mustach syntax.
//! * `{{lookup ... ...}}` get value from array by `@index` or `@key`
//! * `{{#partial ...}} ... {{/partial}}` template reuse, used to replace block with same name
//! * `{{#block ...}} ... {{/block}}` template reuse, used to be replaced by partial with same name, with default content if partial not found.
//! * `{{> ...}}` include template with name
//! * `{{log ...}}` log value with rust logger, default level: INFO. Currently you cannot change the level.
//!

#[macro_use]
extern crate log;

extern crate rustc_serialize as serialize;
extern crate regex;

pub use self::template::{Template, Helper};
pub use self::registry::Registry as Handlebars;
pub use self::render::{Renderable, RenderError, RenderContext};
pub use self::helpers::{HelperDef};
pub use self::context::{Context, JsonRender, JsonTruthy};

mod template;
mod registry;
mod render;
mod helpers;
mod context;
<commit_msg>(fix) rustup<commit_after>#![feature(plugin, core, collections, str_char)]

#![plugin(regex_macros)]

//! # Handlebars
//! Handlebars is a modern and extensible templating solution originally created in the JavaScript world. It's used by many popular frameworks like [Ember.js](http://emberjs.com) and Chaplin. It's also ported to some other platforms such as [Java](https://github.com/jknack/handlebars.java).
//!
//! And this is handlebars Rust implementation, designed for server-side page generation. It's a general-purpose library so you use it for any kind of text generation.
//!
//! ## Handlebars spec
//!
//! ### Base
//!
//! You can go to [Handlebars.js](http://handlebarsjs.com/) website for its syntax. This implementation should be compatible with most parts of the spec, except:
//!
//! * raw helper syntax `{{{raw-helper}}}...{{{/raw-helper}}}` is implemented as block helper raw.
//! * configurable logging (hard-coded to rust native logging, with fixed level `INFO`)
//!
//! ### Extensions
//!
//! We have template reuse facilities supported via built-in helpers `>`, `partial` and `block`.
//!
//! There are two ways to reuse a template:
//!
//! * include (using `>`)
//! * inheritance (using `>` together with `block` and `partial`)
//!
//! Consult [Handlebar.java document about template inheritance](http://jknack.github.io/handlebars.java/reuse.html).
//!
//! ## Usage
//!
//! ### Template Creation and Registration
//!
//! Templates are created from String and registered to `Handlebars` with a name.
//!
//! ```
//!
//! extern crate handlebars;
//!
//! use handlebars::Handlebars;
//!
//! fn main() {
//!   let mut handlebars = Handlebars::new();
//!   let source = "hello {{world}}";
//!
//!   //compile returns an Option, we use unwrap() to deref it directly here
//!   handlebars.register_template_string("helloworld", source.to_string())
//!           .ok().expect("template created");
//! }
//! ```
//!
//! ### Rendering Something
//!
//! I should say that rendering is a little tricky. Since handlebars is originally a JavaScript templating framework. It supports dynamic features like duck-typing, truthy/falsy values. But for a static language like Rust, this is a little difficult. As a solution, I'm using the `serialize::json::Json` internally for data rendering, which seems good by far.
//!
//! That means, if you want to render something, you have to ensure that it implements the `serialize::json::ToJson` trait. Luckily, most built-in types already have trait. However, if you want to render your custom struct, you need to implement this trait manually. (Rust has a deriving facility, but it's just for selected types. Maybe I will add some syntax extensions or macros to simplify this process.)
//!
//! ```
//!
//! extern crate rustc_serialize as serialize;
//! extern crate handlebars;
//!
//! use serialize::json::{Json, ToJson};
//! use std::collections::BTreeMap;
//!
//! use handlebars::Handlebars;
//!
//! struct Person {
//!   name: String,
//!   age: i16,
//! }
//!
//! impl ToJson for Person {
//!   fn to_json(&self) -> Json {
//!     let mut m = BTreeMap::new();
//!     m.insert("name".to_string(), self.name.to_json());
//!     m.insert("age".to_string(), self.age.to_json());
//!     Json::Object(m)
//!   }
//! }
//!
//!
//! fn main() {
//!   let source = "hello {{world}}";
//!
//!   let mut handlebars = Handlebars::new();
//!   handlebars.register_template_string("helloworld", source.to_string())
//!           .ok().expect("template creation failed");
//!
//!   let mut data = Person {
//!       name: "Ning Sun".to_string(),
//!       age: 27
//!   };
//!   let result = handlebars.render("helloworld", &data);
//! }
//! ```
//!
//! ### Custom Helper
//!
//! Handlebars is nothing without helpers. You can also create your own helpers with rust. Helpers in handlebars-rust are custom struct implements the `HelperDef` trait, concretely, the `call` function. For your convenience, most of stateless helpers can be implemented as bare functions.
//!
//! ```
//!
//! extern crate handlebars;
//!
//! use handlebars::{Handlebars, HelperDef, RenderError, RenderContext, Helper, Context};
//!
//! // implement by a structure impls HelperDef
//! #[derive(Copy)]
//! struct SimpleHelper;
//!
//! impl HelperDef for SimpleHelper {
//!   fn call(&self, c: &Context, h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<String, RenderError> {
//!     let param = h.params().get(0).unwrap();
//!
//!     // get value from context data
//!     // rc.get_path() is current json parent path, you should always use it like this
//!     // param is the key of value you want to display
//!     let value = c.navigate(rc.get_path(), param);
//!     Ok(format!("My helper dumps: {} ", value))
//!   }
//! }
//!
//! // implement via bare function
//! fn another_simple_helper (c: &Context, h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<String, RenderError> {
//!     let param = h.params().get(0).unwrap();
//!
//!     // get value from context data
//!     // rc.get_path() is current json parent path, you should always use it like this
//!     // param is the key of value you want to display
//!     let value = c.navigate(rc.get_path(), param);
//!     Ok(format!("My second helper dumps: {} ", value))
//! }
//!
//!
//! fn main() {
//!   let mut handlebars = Handlebars::new();
//!   handlebars.register_helper("simple-helper", Box::new(SimpleHelper));
//!   handlebars.register_helper("another-simple-helper", Box::new(another_simple_helper));
//!
//!   //...
//! }
//! ```
//!
//! #### Arguments of HelpDef
//!
//! You can get data from the `Helper` argument about the template information:
//!
//! * `name()` for the helper name. This is known to you for most situation but if you are defining `helperMissing` or `blockHelperMissing`, this is important.
//! * `params()` is a vector of String as params in helper, like `{{#somehelper param1 param2 param3}}`.
//! * `hash()` is a map of String key and Json value, defined in helper as `{{@somehelper a=1 b="2" c=true}}`.
//! * `template()` gives you the nested template of block helper.
//! * `inverse()` gives you the inversed template of it, inversed template is the template behind `{{else}}`.
//!
//! You can learn more about helpers by looking into source code of built-in helpers.
//!
//! #### Built-in Helpers
//!
//! * `{{#raw}} ... {{/raw}}` escape handlebars expression within the block
//! * `{{#if ...}} ... {{else}} ... {{/if}}` if-else block
//! * `{{#unless ...}} ... {{else}} .. {{/unless}}` if-not-else block
//! * `{{#each ...}} ... {{/each}}` iterates over an array or object. Handlebar-rust doesn't support mustach iteration syntax so use this instead.
//! * `{{#with ...}} ... {{/with}}` change current context. Similar to {{#each}}, used for replace corresponding mustach syntax.
//! * `{{lookup ... ...}}` get value from array by `@index` or `@key`
//! * `{{#partial ...}} ... {{/partial}}` template reuse, used to replace block with same name
//! * `{{#block ...}} ... {{/block}}` template reuse, used to be replaced by partial with same name, with default content if partial not found.
//! * `{{> ...}}` include template with name
//! * `{{log ...}}` log value with rust logger, default level: INFO. Currently you cannot change the level.
//!

#[macro_use]
extern crate log;

extern crate rustc_serialize as serialize;
extern crate regex;

pub use self::template::{Template, Helper};
pub use self::registry::Registry as Handlebars;
pub use self::render::{Renderable, RenderError, RenderContext};
pub use self::helpers::{HelperDef};
pub use self::context::{Context, JsonRender, JsonTruthy};

mod template;
mod registry;
mod render;
mod helpers;
mod context;
<|endoftext|>


<commit_before>#![feature(zero_one, box_syntax)]

extern crate asexp;

pub mod num_expr;
pub mod cond;

use std::fmt::Debug;
use std::cmp::{PartialEq, PartialOrd};

#[derive(Debug, Eq, PartialEq)]
pub enum ExpressionError {
    /// In case of division by zero.
    DivByZero,
    /// In case an invalid variable in references from the expression.
    InvalidVariable,
    /// In case of an invalid operation.
    InvalidOperation,
}

pub trait ElementType: Debug + Copy + Clone + PartialEq + PartialOrd + Default {}

pub trait Expression: Debug + Clone + PartialEq
{
    type Element: ElementType;
    /// Evaluates the expression with the given variables bound.
    fn evaluate(&self, variables: &[Self::Element]) -> Result<Self::Element, ExpressionError>;

    /// Constructs a constant expression. Required by lindenmayer-system.
    fn make_const(elm: Self::Element) -> Self;
}

pub trait Condition: Debug + Clone + PartialEq
{
    type Expr: Expression;
    /// Evaluate the condition with the given variables bound.
    fn evaluate(&self,
                variables: &[<Self::Expr as Expression>::Element])
                -> Result<bool, ExpressionError>;
}
<commit_msg>Add Sized trait to ElementType<commit_after>#![feature(zero_one, box_syntax)]

extern crate asexp;

pub mod num_expr;
pub mod cond;

use std::fmt::Debug;
use std::cmp::{PartialEq, PartialOrd};

#[derive(Debug, Eq, PartialEq)]
pub enum ExpressionError {
    /// In case of division by zero.
    DivByZero,
    /// In case an invalid variable in references from the expression.
    InvalidVariable,
    /// In case of an invalid operation.
    InvalidOperation,
}

pub trait ElementType: Debug + Copy + Clone + PartialEq + PartialOrd + Default + Sized {}

pub trait Expression: Debug + Clone + PartialEq
{
    type Element: ElementType;
    /// Evaluates the expression with the given variables bound.
    fn evaluate(&self, variables: &[Self::Element]) -> Result<Self::Element, ExpressionError>;

    /// Constructs a constant expression. Required by lindenmayer-system.
    fn make_const(elm: Self::Element) -> Self;
}

pub trait Condition: Debug + Clone + PartialEq
{
    type Expr: Expression;
    /// Evaluate the condition with the given variables bound.
    fn evaluate(&self,
                variables: &[<Self::Expr as Expression>::Element])
                -> Result<bool, ExpressionError>;
}
<|endoftext|>


<commit_before>#![feature(trace_macros)]
#![feature(log_syntax)]

extern crate num;
extern crate rand;
extern crate rutorch;
#[macro_use]
extern crate modparse_derive;
extern crate linked_hash_map;

mod nn;
use rutorch::*;
use nn::*;
use std::ops::{Index, IndexMut};
//use std::convert::From;
use std::cmp::max;
use std::slice;

trait Storage {
    fn new() -> Self;
    fn sized(len: isize) -> Self;
}

pub struct FloatStorage {
    t: *mut THFloatStorage,
}

impl Storage for FloatStorage {
    fn new() -> Self {
        unsafe { FloatStorage { t: THFloatStorage_new() } }
    }
    fn sized(size: isize) -> Self {
        unsafe { FloatStorage { t: THFloatStorage_newWithSize(size) } }
    }
}
// XXX annotate with lifetime for safety's sake
impl FloatStorage {
    fn into_slice(&self) -> &[f32] {
        unsafe { slice::from_raw_parts((*self.t).data, (*self.t).size as usize) }
    }
    fn into_slice_mut(&mut self) -> &mut [f32] {
        unsafe { slice::from_raw_parts_mut((*self.t).data, (*self.t).size as usize) }
    }
    pub fn iter(&self) -> slice::Iter<f32> {
        self.into_slice().iter()
    }
    pub fn iter_mut(&mut self) -> slice::IterMut<f32> {
        self.into_slice_mut().iter_mut()
    }
}

impl Index<isize> for FloatStorage {
    type Output = f32;

    fn index(&self, idx: isize) -> &f32 {
        unsafe { &*(*self.t).data.offset(idx) }
    }
}

impl IndexMut<isize> for FloatStorage {
    fn index_mut(&mut self, idx: isize) -> &mut f32 {
        unsafe { &mut *(*self.t).data.offset(idx) }
    }
}

//fn from(args: &ArgsArray<T>) -> Self;

trait Tensor<'a> {
    fn new() -> Self;
    fn sized(size: &'a [isize]) -> Self;
    fn randn(dims: &'a [isize]) -> Self;
}

pub struct FloatTensor {
    t: *mut THFloatTensor,
    storage: FloatStorage,
    dims: Vec<isize>,
}

pub struct Parameter {}

impl<'a> Tensor<'a> for FloatTensor {
    fn new() -> Self {
        unsafe {
            FloatTensor {
                t: THFloatTensor_new(),
                storage: FloatStorage::new(),
                dims: Vec::new(),
            }
        }
    }

    fn sized(dims: &'a [isize]) -> Self {
        let size = dims.iter().product();
        let storage = FloatStorage::sized(size);
        let strides = vec![1; dims.len()];
        let mut t = THFloatTensor {
            size: dims.clone().as_ptr() as *mut ::std::os::raw::c_long,
            stride: strides.as_ptr() as *mut ::std::os::raw::c_long,
            nDimension: dims.len() as i32,
            storage: storage.t,
            storageOffset: 0,
            refcount: 1,
            flag: TH_TENSOR_REFCOUNTED as i8,
        };
        FloatTensor {
            t: &mut t,
            storage: storage,
            dims: Vec::from(dims),
        }
    }
    fn randn(dims: &'a [isize]) -> Self {
        /* XXX */
        let mut t = FloatTensor::sized(dims);
        for x in t.storage.iter_mut() {
            *x = rand::random::<f32>()
        }
        t
    }
}

impl<'a> Index<&'a [isize]> for FloatTensor {
    type Output = f32;

    fn index(&self, idx: &'a [isize]) -> &f32 {
        let mut index: isize = 0;
        let lastidx = max(0, idx.len() as isize - 1) as usize;
        if idx.len() != self.dims.len() {
            panic!("bad dimlen")
        }
        for i in 0..lastidx {
            if idx[i] >= self.dims[i] {
                panic!("bad dimlen")
            }
            index += idx[i] * self.dims[i]
        }
        if idx[lastidx] >= self.dims[lastidx] {
            panic!("bad dimlen")
        }
        index += idx[lastidx];
        &self.storage[index]
    }
}

impl<'a> IndexMut<&'a [isize]> for FloatTensor {
    fn index_mut(&mut self, idx: &'a [isize]) -> &mut f32 {
        let mut index: isize = 0;
        let lastidx = max(0, idx.len() as isize - 1) as usize;
        if idx.len() != self.dims.len() {
            panic!("bad dimlen")
        }
        for i in 0..lastidx {
            if idx[i] >= self.dims[i] {
                panic!("bad dimlen")
            }
            index += idx[i] * self.dims[i]
        }
        if idx[lastidx] >= self.dims[lastidx] {
            panic!("bad dimlen")
        }
        index += idx[lastidx];
        &mut self.storage[index]
    }
}

/*
    def __init__(self):
        self._backend = thnn_backend
        self._parameters = OrderedDict()
        self._buffers = OrderedDict()
        self._backward_hooks = OrderedDict()
        self._forward_hooks = OrderedDict()
        self._modules = OrderedDict()
        self.training = True
*/

/*
impl fmt::Display for FloatTensor {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match (*self.t).size
		write!(f, "[torchrs.FloatTensor of size ]")
	}
}
*/
#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn it_works() {}
}
<commit_msg>move module test code<commit_after>#![feature(trace_macros)]
#![feature(log_syntax)]

extern crate num;
extern crate rand;
extern crate rutorch;
#[macro_use]
extern crate modparse_derive;
extern crate linked_hash_map;

pub mod nn;
use rutorch::*;
use std::ops::{Index, IndexMut};
//use std::convert::From;
use std::cmp::max;
use std::slice;

trait Storage {
    fn new() -> Self;
    fn sized(len: isize) -> Self;
}

pub struct FloatStorage {
    t: *mut THFloatStorage,
}

impl Storage for FloatStorage {
    fn new() -> Self {
        unsafe { FloatStorage { t: THFloatStorage_new() } }
    }
    fn sized(size: isize) -> Self {
        unsafe { FloatStorage { t: THFloatStorage_newWithSize(size) } }
    }
}
// XXX annotate with lifetime for safety's sake
impl FloatStorage {
    fn into_slice(&self) -> &[f32] {
        unsafe { slice::from_raw_parts((*self.t).data, (*self.t).size as usize) }
    }
    fn into_slice_mut(&mut self) -> &mut [f32] {
        unsafe { slice::from_raw_parts_mut((*self.t).data, (*self.t).size as usize) }
    }
    pub fn iter(&self) -> slice::Iter<f32> {
        self.into_slice().iter()
    }
    pub fn iter_mut(&mut self) -> slice::IterMut<f32> {
        self.into_slice_mut().iter_mut()
    }
}

impl Index<isize> for FloatStorage {
    type Output = f32;

    fn index(&self, idx: isize) -> &f32 {
        unsafe { &*(*self.t).data.offset(idx) }
    }
}

impl IndexMut<isize> for FloatStorage {
    fn index_mut(&mut self, idx: isize) -> &mut f32 {
        unsafe { &mut *(*self.t).data.offset(idx) }
    }
}

//fn from(args: &ArgsArray<T>) -> Self;

trait Tensor<'a> {
    fn new() -> Self;
    fn sized(size: &'a [isize]) -> Self;
    fn randn(dims: &'a [isize]) -> Self;
}

pub struct FloatTensor {
    t: *mut THFloatTensor,
    storage: FloatStorage,
    dims: Vec<isize>,
}

pub struct Parameter {}

impl<'a> Tensor<'a> for FloatTensor {
    fn new() -> Self {
        unsafe {
            FloatTensor {
                t: THFloatTensor_new(),
                storage: FloatStorage::new(),
                dims: Vec::new(),
            }
        }
    }

    fn sized(dims: &'a [isize]) -> Self {
        let size = dims.iter().product();
        let storage = FloatStorage::sized(size);
        let strides = vec![1; dims.len()];
        let mut t = THFloatTensor {
            size: dims.clone().as_ptr() as *mut ::std::os::raw::c_long,
            stride: strides.as_ptr() as *mut ::std::os::raw::c_long,
            nDimension: dims.len() as i32,
            storage: storage.t,
            storageOffset: 0,
            refcount: 1,
            flag: TH_TENSOR_REFCOUNTED as i8,
        };
        FloatTensor {
            t: &mut t,
            storage: storage,
            dims: Vec::from(dims),
        }
    }
    fn randn(dims: &'a [isize]) -> Self {
        /* XXX */
        let mut t = FloatTensor::sized(dims);
        for x in t.storage.iter_mut() {
            *x = rand::random::<f32>()
        }
        t
    }
}

impl<'a> Index<&'a [isize]> for FloatTensor {
    type Output = f32;

    fn index(&self, idx: &'a [isize]) -> &f32 {
        let mut index: isize = 0;
        let lastidx = max(0, idx.len() as isize - 1) as usize;
        if idx.len() != self.dims.len() {
            panic!("bad dimlen")
        }
        for i in 0..lastidx {
            if idx[i] >= self.dims[i] {
                panic!("bad dimlen")
            }
            index += idx[i] * self.dims[i]
        }
        if idx[lastidx] >= self.dims[lastidx] {
            panic!("bad dimlen")
        }
        index += idx[lastidx];
        &self.storage[index]
    }
}

impl<'a> IndexMut<&'a [isize]> for FloatTensor {
    fn index_mut(&mut self, idx: &'a [isize]) -> &mut f32 {
        let mut index: isize = 0;
        let lastidx = max(0, idx.len() as isize - 1) as usize;
        if idx.len() != self.dims.len() {
            panic!("bad dimlen")
        }
        for i in 0..lastidx {
            if idx[i] >= self.dims[i] {
                panic!("bad dimlen")
            }
            index += idx[i] * self.dims[i]
        }
        if idx[lastidx] >= self.dims[lastidx] {
            panic!("bad dimlen")
        }
        index += idx[lastidx];
        &mut self.storage[index]
    }
}

/*
    def __init__(self):
        self._backend = thnn_backend
        self._parameters = OrderedDict()
        self._buffers = OrderedDict()
        self._backward_hooks = OrderedDict()
        self._forward_hooks = OrderedDict()
        self._modules = OrderedDict()
        self.training = True
*/

/*
impl fmt::Display for FloatTensor {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match (*self.t).size
		write!(f, "[torchrs.FloatTensor of size ]")
	}
}
*/
#[cfg(test)]
mod tests {
    use super::*;
    use nn::*;

#[derive(ModParse)]

pub struct MyModSmallA<'a> {
	delegate: Module<'a>,
}

impl <'a>MyModSmallA<'a> {
	pub fn new() -> Self {
		let mut t = MyModSmallA {delegate: Module::new()};
		t.init_module();
		t
	}
}

#[derive(ModParse)]
pub struct MyModBig<'a> {
	delegate: Module<'a>,
	#[module]
	a: Linear<'a> ,
	#[module]
	b: MyModSmallA<'a>
}

impl <'a>ModIntf<'a> for MyModBig<'a> {
	fn delegate(&mut self) -> &mut Module<'a> {
				&mut self.delegate

	}
	fn forward(&mut self /* Tensor */ ) /* -> Tensor */{}
}
impl <'a>ModIntf<'a> for MyModSmallA<'a> {
	fn delegate(&mut self) -> &mut Module<'a> {
				&mut self.delegate

	}
	fn forward(&mut self /* Tensor */ ) /* -> Tensor */{}
}
impl <'a> MyModBig<'a> {
	pub fn new() -> MyModBig<'a>  {
		let mut t = MyModBig {delegate: Module::new(),
			a: Linear::new(), b: MyModSmallA::new()} ;
		t.init_module();
		t
	}
}

    #[test]
    fn it_works() {
    	let x = MyModBig::new();
    }
}
<|endoftext|>