<commit_before>use header::Tag;
use ::Reader;
use core::slice;

#[derive(Debug, PartialEq)]
pub struct FramebufferTag<'a> {
    pub address: u64,
    pub pitch: u32,
    pub width: u32,
    pub height: u32,
    pub bpp: u8,
    pub buffer_type: FramebufferType<'a>
}

#[derive(Debug, PartialEq)]
pub enum FramebufferType<'a> {
    Indexed {
        palette: &'a [FramebufferColor]
    },
    RGB {
        red: FramebufferField,
        green: FramebufferField,
        blue: FramebufferField
    },
    Text
}

#[derive(Debug, PartialEq)]
pub struct FramebufferField {
    pub position: u8,
    pub size: u8
}

#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C, packed)]
pub struct FramebufferColor {
    pub red: u8,
    pub green: u8,
    pub blue: u8
}

pub fn framebuffer_tag<'a>(tag: &'a Tag) -> FramebufferTag<'a> {
    let mut reader = Reader::new(tag as *const Tag);
    reader.skip(8);
    let address = reader.read_u64();
    let pitch = reader.read_u32();
    let width = reader.read_u32();
    let height = reader.read_u32();
    let bpp = reader.read_u8();
    let type_no = reader.read_u8();
    reader.skip(2); // In the multiboot spec, it has this listed as a u8 _NOT_ a u16.
                    // Reading the GRUB2 source code reveals it is in fact a u16.
    let buffer_type = match type_no {
        0 =>  {
            let num_colors = reader.read_u32();
            let palette = unsafe {
                slice::from_raw_parts(reader.read_u32() as usize as *const FramebufferColor, num_colors as usize)
            } as &'static [FramebufferColor];
            FramebufferType::Indexed { palette }
        },
        1 => {
            let red_pos = reader.read_u8();     // These refer to the bit positions of the MSB of each field
            let red_mask = reader.read_u8();    // And then the length of the field from MSB to LSB
            let green_pos = reader.read_u8();
            let green_mask = reader.read_u8();
            let blue_pos = reader.read_u8();
            let blue_mask = reader.read_u8();
            FramebufferType::RGB {
                red: FramebufferField { position: red_pos, size: red_mask },
                green: FramebufferField { position: green_pos, size: green_mask },
                blue: FramebufferField { position: blue_pos, size: blue_mask }
            }
        },
        2 => FramebufferType::Text,
        _ => panic!("Unknown framebuffer type: {}", type_no)
    };

    FramebufferTag {
        address,
        pitch,
        width,
        height,
        bpp,
        buffer_type
    }
}
<commit_msg>Use 'a instead of 'static in framebuffer.rs<commit_after>use header::Tag;
use ::Reader;
use core::slice;

#[derive(Debug, PartialEq)]
pub struct FramebufferTag<'a> {
    pub address: u64,
    pub pitch: u32,
    pub width: u32,
    pub height: u32,
    pub bpp: u8,
    pub buffer_type: FramebufferType<'a>
}

#[derive(Debug, PartialEq)]
pub enum FramebufferType<'a> {
    Indexed {
        palette: &'a [FramebufferColor]
    },
    RGB {
        red: FramebufferField,
        green: FramebufferField,
        blue: FramebufferField
    },
    Text
}

#[derive(Debug, PartialEq)]
pub struct FramebufferField {
    pub position: u8,
    pub size: u8
}

#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C, packed)]
pub struct FramebufferColor {
    pub red: u8,
    pub green: u8,
    pub blue: u8
}

pub fn framebuffer_tag<'a>(tag: &'a Tag) -> FramebufferTag<'a> {
    let mut reader = Reader::new(tag as *const Tag);
    reader.skip(8);
    let address = reader.read_u64();
    let pitch = reader.read_u32();
    let width = reader.read_u32();
    let height = reader.read_u32();
    let bpp = reader.read_u8();
    let type_no = reader.read_u8();
    reader.skip(2); // In the multiboot spec, it has this listed as a u8 _NOT_ a u16.
                    // Reading the GRUB2 source code reveals it is in fact a u16.
    let buffer_type = match type_no {
        0 =>  {
            let num_colors = reader.read_u32();
            let palette = unsafe {
                slice::from_raw_parts(reader.read_u32() as usize as *const FramebufferColor, num_colors as usize)
            } as &'a [FramebufferColor];
            FramebufferType::Indexed { palette }
        },
        1 => {
            let red_pos = reader.read_u8();     // These refer to the bit positions of the MSB of each field
            let red_mask = reader.read_u8();    // And then the length of the field from MSB to LSB
            let green_pos = reader.read_u8();
            let green_mask = reader.read_u8();
            let blue_pos = reader.read_u8();
            let blue_mask = reader.read_u8();
            FramebufferType::RGB {
                red: FramebufferField { position: red_pos, size: red_mask },
                green: FramebufferField { position: green_pos, size: green_mask },
                blue: FramebufferField { position: blue_pos, size: blue_mask }
            }
        },
        2 => FramebufferType::Text,
        _ => panic!("Unknown framebuffer type: {}", type_no)
    };

    FramebufferTag {
        address,
        pitch,
        width,
        height,
        bpp,
        buffer_type
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::path::PathBuf;

fn main() {
    static ENV_CIRCT_DIR: &str = "CIRCT_SYS_CIRCT_DIR";
    static ENV_CIRCT_BUILD_DIR: &str = "CIRCT_SYS_CIRCT_BUILD_DIR";
    static ENV_LLVM_DIR: &str = "CIRCT_SYS_LLVM_DIR";
    static ENV_LLVM_BUILD_DIR: &str = "CIRCT_SYS_LLVM_BUILD_DIR";

    println!("cargo:rerun-if-env-changed={}", &*ENV_CIRCT_DIR);
    println!("cargo:rerun-if-env-changed={}", &*ENV_CIRCT_BUILD_DIR);
    println!("cargo:rerun-if-env-changed={}", &*ENV_LLVM_DIR);
    println!("cargo:rerun-if-env-changed={}", &*ENV_LLVM_BUILD_DIR);

    let circt_dir = PathBuf::from(env::var(ENV_CIRCT_DIR).unwrap());
    let circt_build_dir = env::var(ENV_CIRCT_BUILD_DIR)
        .map(PathBuf::from)
        .unwrap_or_else(|_| circt_dir.join("build"));
    let llvm_dir = env::var(ENV_LLVM_DIR)
        .map(PathBuf::from)
        .unwrap_or_else(|_| circt_dir.join("llvm"));
    let llvm_build_dir = env::var(ENV_LLVM_BUILD_DIR)
        .map(PathBuf::from)
        .unwrap_or_else(|_| llvm_dir.join("build"));

    // CIRCT/LLVM/MLIR libraries
    for name in &[circt_build_dir.join("lib"), llvm_build_dir.join("lib")] {
        println!("cargo:rustc-link-search=native={}", name.display());
    }
    for name in &[
        "CIRCTCAPIComb",
        "CIRCTCAPIHW",
        "CIRCTCAPILLHD",
        "CIRCTCAPISV",
        "CIRCTCAPISeq",
        "CIRCTComb",
        "CIRCTHW",
        "CIRCTLLHD",
        "CIRCTSV",
        "CIRCTSeq",
        "LLVMCore",
        "LLVMSupport",
        "MLIRAnalysis",
        "MLIRCAPIIR",
        "MLIRCAPIStandard",
        "MLIRIR",
        "MLIRPDL",
        "MLIRPDLInterp",
        "MLIRPDLToPDLInterp",
        "MLIRPass",
        "MLIRRewrite",
        "MLIRControlFlowInterfaces",
        "MLIRSideEffectInterfaces",
        "MLIRCallInterfaces",
        "MLIRSupport",
        "MLIRTransformUtils",
        "MLIRStandard",
        "MLIRTransforms",
        "MLIRTranslation",
    ] {
        println!("cargo:rustc-link-lib=static={}", name);
    }

    // System libraries
    let system_libraries = [
        "stdc++", // llvm-config --system-libs --link-static
        "rt", "dl", "pthread", "m", "z", "tinfo", "xml2",
    ];
    for name in &system_libraries {
        println!("cargo:rustc-link-lib=dylib={}", name);
    }

    // Bindings
    println!("cargo:rerun-if-changed=wrapper.h");
    let bindings = bindgen::Builder::default()
        .header("wrapper.h")
        .clang_arg("-I")
        .clang_arg(circt_dir.join("include").display().to_string())
        .clang_arg("-I")
        .clang_arg(circt_build_dir.join("include").display().to_string())
        .clang_arg("-I")
        .clang_arg(llvm_dir.join("llvm/include").display().to_string())
        .clang_arg("-I")
        .clang_arg(llvm_dir.join("mlir/include").display().to_string())
        .clang_arg("-I")
        .clang_arg(llvm_build_dir.join("include").display().to_string())
        .clang_arg("-I")
        .clang_arg(
            llvm_build_dir
                .join("tools/mlir/include")
                .display()
                .to_string(),
        )
        .parse_callbacks(Box::new(bindgen::CargoCallbacks))
        .generate()
        .expect("Unable to generate bindings");

    // Write the bindings to the $OUT_DIR/bindings.rs file.
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}
<commit_msg>mlir: Compile order fixes<commit_after>use std::env;
use std::path::PathBuf;

fn main() {
    static ENV_CIRCT_DIR: &str = "CIRCT_SYS_CIRCT_DIR";
    static ENV_CIRCT_BUILD_DIR: &str = "CIRCT_SYS_CIRCT_BUILD_DIR";
    static ENV_LLVM_DIR: &str = "CIRCT_SYS_LLVM_DIR";
    static ENV_LLVM_BUILD_DIR: &str = "CIRCT_SYS_LLVM_BUILD_DIR";

    println!("cargo:rerun-if-env-changed={}", &*ENV_CIRCT_DIR);
    println!("cargo:rerun-if-env-changed={}", &*ENV_CIRCT_BUILD_DIR);
    println!("cargo:rerun-if-env-changed={}", &*ENV_LLVM_DIR);
    println!("cargo:rerun-if-env-changed={}", &*ENV_LLVM_BUILD_DIR);

    let circt_dir = PathBuf::from(env::var(ENV_CIRCT_DIR).unwrap());
    let circt_build_dir = env::var(ENV_CIRCT_BUILD_DIR)
        .map(PathBuf::from)
        .unwrap_or_else(|_| circt_dir.join("build"));
    let llvm_dir = env::var(ENV_LLVM_DIR)
        .map(PathBuf::from)
        .unwrap_or_else(|_| circt_dir.join("llvm"));
    let llvm_build_dir = env::var(ENV_LLVM_BUILD_DIR)
        .map(PathBuf::from)
        .unwrap_or_else(|_| llvm_dir.join("build"));

    // CIRCT/LLVM/MLIR libraries
    for name in &[circt_build_dir.join("lib"), llvm_build_dir.join("lib")] {
        println!("cargo:rustc-link-search=native={}", name.display());
    }
    for name in &[
        "CIRCTCAPIComb",
        "CIRCTCAPIHW",
        "CIRCTCAPILLHD",
        "CIRCTCAPISV",
        "CIRCTCAPISeq",
        "CIRCTComb",
        "CIRCTHW",
        "CIRCTLLHD",
        "CIRCTSV",
        "CIRCTSeq",
        "LLVMCore",
        "LLVMSupport",
        "MLIRAnalysis",
        "MLIRArithmetic",
        "MLIRCAPIIR",
        "MLIRCAPIStandard",
        "MLIRCallInterfaces",
        "MLIRControlFlowInterfaces",
        "MLIRIR",
        "MLIRInferTypeOpInterface",
        "MLIRPDL",
        "MLIRPDLInterp",
        "MLIRPDLToPDLInterp",
        "MLIRParser",
        "MLIRPass",
        "MLIRRewrite",
        "MLIRSideEffectInterfaces",
        "MLIRStandard",
        "MLIRSupport",
        "MLIRTransformUtils",
        "MLIRTransforms",
        "MLIRTranslation",
    ] {
        println!("cargo:rustc-link-lib=static={}", name);
    }

    // System libraries
    let system_libraries = [
        "stdc++", // llvm-config --system-libs --link-static
        "rt", "dl", "pthread", "m", "z", "tinfo", "xml2",
    ];
    for name in &system_libraries {
        println!("cargo:rustc-link-lib=dylib={}", name);
    }

    // Bindings
    println!("cargo:rerun-if-changed=wrapper.h");
    let bindings = bindgen::Builder::default()
        .header("wrapper.h")
        .clang_arg("-I")
        .clang_arg(circt_dir.join("include").display().to_string())
        .clang_arg("-I")
        .clang_arg(circt_build_dir.join("include").display().to_string())
        .clang_arg("-I")
        .clang_arg(llvm_dir.join("llvm/include").display().to_string())
        .clang_arg("-I")
        .clang_arg(llvm_dir.join("mlir/include").display().to_string())
        .clang_arg("-I")
        .clang_arg(llvm_build_dir.join("include").display().to_string())
        .clang_arg("-I")
        .clang_arg(
            llvm_build_dir
                .join("tools/mlir/include")
                .display()
                .to_string(),
        )
        .parse_callbacks(Box::new(bindgen::CargoCallbacks))
        .generate()
        .expect("Unable to generate bindings");

    // Write the bindings to the $OUT_DIR/bindings.rs file.
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}
<|endoftext|>


<commit_before>
extern crate sysfs_gpio;
extern crate sysfs_pwm;

use self::sysfs_gpio::{Direction, Pin};
use self::sysfs_pwm::{Pwm};
use ::std::error::Error;
use std::thread;
use std::time;

use super::{PinProxyContract,PwmProxyContract,DirectionProxied,ProxyError,ProxyResult};

pub struct PinProxy {
	pin : Pin,
}

impl PinProxyContract for PinProxy
{
	fn new(pin_num: u64) -> PinProxy {
		PinProxy{ pin: Pin::new(pin_num) }
	}

	fn export(&self) ->  ProxyResult<()>{
		match self.pin.export()
		{
			Ok(()) => Ok(()),
			Err(result) => {println!("{}",result.description());
				Err(ProxyError::MonErreur)},
		}
	}

	fn unexport(&self) ->  ProxyResult<()> {
		match self.pin.unexport()
		{
			Ok(()) => Ok(()),
			Err(result) => {println!("{}",result.description());
				Err(ProxyError::MonErreur)},
		}
	}

	fn set_value(&self, value: u8) ->  ProxyResult<()> {
		match self.pin.set_value(value)
		{
			Ok(()) => Ok(()),
			Err(result) => {println!("{}",result.description());
				Err(ProxyError::MonErreur)},
		}
	}

	fn set_direction(&self, dir: DirectionProxied) ->  ProxyResult<()>{
		let dirmapped =  match dir {
										DirectionProxied::In =>  Direction::In,
										DirectionProxied::Out => Direction::Out,
										DirectionProxied::High => Direction::High,
										DirectionProxied::Low => Direction::Low,
									};
		match self.pin.set_direction(dirmapped)
		{
			Ok(()) => Ok(()),
			Err(result) => {println!("{}",result.description());
				Err(ProxyError::MonErreur)},
		}
	}
}

pub struct PwmProxy {
	pwm : Pwm,
}

impl PwmProxyContract for PwmProxy
{
	fn new(chip: u32, number: u32) -> ProxyResult<PwmProxy>{

		match Pwm::new(chip, number) {
			Ok(pwm) => Ok(PwmProxy{ pwm: pwm}),
			Err(result) => {println!("{}",result.description());
				Err(ProxyError::MonErreur)},
		}
	}

	fn export(&self) ->  ProxyResult<()>{
		match self.pwm.export()
		{
			Ok(()) => Ok(()),
			Err(result) => {println!("{}",result.description());
				Err(ProxyError::MonErreur)},
		}
	}

	fn unexport(&self) ->  ProxyResult<()> {
		match self.pwm.unexport()
		{
			Ok(()) => Ok(()),
			Err(result) => {println!("{}",result.description());
				Err(ProxyError::MonErreur)},
		}
	}

	fn enable(&self, enable: bool) -> ProxyResult<()>
	{
		match self.pwm.enable(enable)
		{
			Ok(()) => Ok(()),
			Err(result) => {println!("{} caused by {}",result.description(),result.cause().unwrap());
				Err(ProxyError::MonErreur)},
		}
	}

	fn set_duty_cycle_ns(&self, duty_cycle_ns: u32) -> ProxyResult<()>
	{
		match self.pwm.set_duty_cycle_ns(duty_cycle_ns)
		{
			Ok(()) => {println!("setting dutycycle {}",duty_cycle_ns); Ok(())},
			Err(result) => {println!("{}",result.description());
				Err(ProxyError::MonErreur)},
		}
	}

	fn set_period_ns(&self, period_ns: u32) -> ProxyResult<()>
	{
		match self.pwm.set_period_ns(period_ns)
		{
			Ok(()) => Ok(()),
			Err(result) => {println!("{}",result.description());
				Err(ProxyError::MonErreur)},
		}
	}

	fn get_period_ns(&self) -> ProxyResult<u32>
	{
		match self.pwm.get_period_ns()
		{
			Ok(result) => Ok(result),
			Err(result) => {println!("{}",result.description());
				Err(ProxyError::MonErreur)},
		}

	}

	fn increase_to_max(&self, step : f32)
	{
		println!("step {}",step);
		let mut duty_cycle = 0.0;
		match self.pwm.get_period_ns()
		{
			Ok(period_ns) => {
			println!("period {}",period_ns);
				while duty_cycle < 1.0 {
					println!("duty cycle {}",duty_cycle);
					println!("set duty cycle ns{}",(duty_cycle * period_ns as f32) as u32);
					self.pwm.set_duty_cycle_ns((duty_cycle * period_ns as f32) as u32).unwrap();
					duty_cycle += step;
					thread::sleep(time::Duration::from_millis(50));
				}
				self.pwm.set_duty_cycle_ns(period_ns).unwrap()
			}
			Err(result) => {println!("{}",result.description())}
		}
	}

	fn decrease_to_minimum(&self, step : f32)
	{
		println!("step {}",step);
		let mut duty_cycle = 1.0;
		match self.pwm.get_period_ns()
		{
			Ok(period_ns) => {
			println!("period {}",period_ns);
				while duty_cycle > 0.0 {
					println!("duty cycle {}",duty_cycle);
					println!("set duty cycle ns{}",(duty_cycle * period_ns as f32) as u32);
					self.pwm.set_duty_cycle_ns((duty_cycle * period_ns as f32) as u32).unwrap();
					duty_cycle -= step;
					thread::sleep(time::Duration::from_millis(50));
				}
				self.pwm.set_duty_cycle_ns(0).unwrap()
			}
			Err(result) => {println!("{}",result.description())}
		}
	}
}<commit_msg>modif<commit_after>
extern crate sysfs_gpio;
extern crate sysfs_pwm;

use self::sysfs_gpio::{Direction, Pin};
use self::sysfs_pwm::{Pwm};
use ::std::error::Error;
use std::thread;
use std::time;

use super::{PinProxyContract,PwmProxyContract,DirectionProxied,ProxyError,ProxyResult};

pub struct PinProxy {
	pin : Pin,
}

impl PinProxyContract for PinProxy
{
	fn new(pin_num: u64) -> PinProxy {
		PinProxy{ pin: Pin::new(pin_num) }
	}

	fn export(&self) ->  ProxyResult<()>{
		match self.pin.export()
		{
			Ok(()) => Ok(()),
			Err(result) => {println!("{}",result.description());
				Err(ProxyError::MonErreur)},
		}
	}

	fn unexport(&self) ->  ProxyResult<()> {
		match self.pin.unexport()
		{
			Ok(()) => Ok(()),
			Err(result) => {println!("{}",result.description());
				Err(ProxyError::MonErreur)},
		}
	}

	fn set_value(&self, value: u8) ->  ProxyResult<()> {
		match self.pin.set_value(value)
		{
			Ok(()) => Ok(()),
			Err(result) => {println!("{}",result.description());
				Err(ProxyError::MonErreur)},
		}
	}

	fn set_direction(&self, dir: DirectionProxied) ->  ProxyResult<()>{
		let dirmapped =  match dir {
										DirectionProxied::In =>  Direction::In,
										DirectionProxied::Out => Direction::Out,
										DirectionProxied::High => Direction::High,
										DirectionProxied::Low => Direction::Low,
									};
		match self.pin.set_direction(dirmapped)
		{
			Ok(()) => Ok(()),
			Err(result) => {println!("{}",result.description());
				Err(ProxyError::MonErreur)},
		}
	}
}

pub struct PwmProxy {
	pwm : Pwm,
}

impl PwmProxyContract for PwmProxy
{
	fn new(chip: u32, number: u32) -> ProxyResult<PwmProxy>{

		match Pwm::new(chip, number) {
			Ok(pwm) => Ok(PwmProxy{ pwm: pwm}),
			Err(result) => {println!("{}",result.description());
				Err(ProxyError::MonErreur)},
		}
	}

	fn export(&self) ->  ProxyResult<()>{
		match self.pwm.export()
		{
			Ok(()) => Ok(()),
			Err(result) => {println!("{}",result.description());
				Err(ProxyError::MonErreur)},
		}
	}

	fn unexport(&self) ->  ProxyResult<()> {
		match self.pwm.unexport()
		{
			Ok(()) => Ok(()),
			Err(result) => {println!("{}",result.description());
				Err(ProxyError::MonErreur)},
		}
	}

	fn enable(&self, enable: bool) -> ProxyResult<()>
	{
		match self.pwm.enable(enable)
		{
			Ok(()) => Ok(()),
			Err(result) => {println!("{} caused by {}",result.description(),result.cause().unwrap());
				Err(ProxyError::MonErreur)},
		}
	}

	fn set_duty_cycle_ns(&self, duty_cycle_ns: u32) -> ProxyResult<()>
	{
		match self.pwm.set_duty_cycle_ns(duty_cycle_ns)
		{
			Ok(()) => {println!("setting dutycycle {}",duty_cycle_ns); Ok(())},
			Err(result) => {println!("{}",result.description());
				Err(ProxyError::MonErreur)},
		}
	}

	fn set_period_ns(&self, period_ns: u32) -> ProxyResult<()>
	{
		match self.pwm.set_period_ns(period_ns)
		{
			Ok(()) => Ok(()),
			Err(result) => {println!("{}",result.description());
				Err(ProxyError::MonErreur)},
		}
	}

	fn get_period_ns(&self) -> ProxyResult<u32>
	{
		match self.pwm.get_period_ns()
		{
			Ok(result) => Ok(result),
			Err(result) => {println!("{}",result.description());
				Err(ProxyError::MonErreur)},
		}

	}

	fn increase_to_max(&self, step : f32)
	{
		println!("step {}",step);
		let mut duty_cycle = 0.0;
		match self.pwm.get_period_ns()
		{
			Ok(period_ns) => {
			println!("period {}",period_ns);
				while duty_cycle < 1.0 {
					println!("duty cycle {}",duty_cycle);
					println!("set duty cycle ns{}",(duty_cycle * period_ns as f32) as u32);
					self.pwm.set_duty_cycle_ns((duty_cycle * period_ns as f32) as u32).unwrap();
					duty_cycle += step;
					thread::sleep(time::Duration::from_millis(300));
				}
				self.pwm.set_duty_cycle_ns(period_ns).unwrap()
			}
			Err(result) => {println!("{}",result.description())}
		}
	}

	fn decrease_to_minimum(&self, step : f32)
	{
		println!("step {}",step);
		let mut duty_cycle = 1.0;
		match self.pwm.get_period_ns()
		{
			Ok(period_ns) => {
			println!("period {}",period_ns);
				while duty_cycle > 0.0 {
					println!("duty cycle {}",duty_cycle);
					println!("set duty cycle ns{}",(duty_cycle * period_ns as f32) as u32);
					self.pwm.set_duty_cycle_ns((duty_cycle * period_ns as f32) as u32).unwrap();
					duty_cycle -= step;
					thread::sleep(time::Duration::from_millis(300));
				}
				self.pwm.set_duty_cycle_ns(0).unwrap()
			}
			Err(result) => {println!("{}",result.description())}
		}
	}
}<|endoftext|>


<commit_before>extern crate websocket;

use std;
use std::sync::{Arc, Mutex};
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

use websocket::{Message, Sender, Receiver};
use websocket::message::Type;
use websocket::client::request::Url;

use hyper::header::{Cookie};

use rustc_serialize::json;
use rustc_serialize::json::Json;

use lila;

// making a move
// out {"t":"move","d":{"from":"e2","to":"e4","b":1}}
// in {t: "ack"}
// in {"v":1,"t":"move","d":{"uci":"e2e4","san":"e4","fen":"rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR","ply":1,"clock":{"white":172800,"black":172800},"dests":{"b8":"a6c6","g8":"f6h6","h7":"h6h5","d7":"d6d5","g7":"g6g5","c7":"c6c5","f7":"f6f5","b7":"b6b5","e7":"e6e5","a7":"a6a5"},"crazyhouse":{"pockets":[{},{}]}}}
// other player moved
// in {"v":2,"t":"move","d":{"uci":"g7g5","san":"g5","fen":"rnbqkbnr/pppppp1p/8/6p1/4P3/8/PPPP1PPP/RNBQKBNR","ply":2,"clock":{"white":172800,"black":172800},"dests":{"a2":"a3a4","g1":"f3h3e2","d1":"e2f3g4h5","e1":"e2","d2":"d3d4","b1":"a3c3","e4":"e5","f1":"e2d3c4b5a6","h2":"h3h4","b2":"b3b4","f2":"f3f4","c2":"c3c4","g2":"g3g4"},"crazyhouse":{"pockets":[{},{}]}}}

#[derive(RustcEncodable)]
struct PingPacket {
    t: String,
    v: i64
}

impl PingPacket {
    pub fn new(version: i64) -> PingPacket {
        PingPacket {
            t: "p".to_string(),
            v: version
        }
    }

    pub fn to_message(&self) -> Message<'static> {
        Message::text(json::encode(self).unwrap())
    }
}

#[allow(dead_code)]
#[derive(RustcEncodable)]
pub struct MovePacket {
    t: String,
    d: Dest,
}

#[allow(dead_code)]
#[derive(RustcEncodable)]
pub struct Dest {
    pub from: String,
    pub to: String,
    // pub: i8, // bool, but 0 or 1
}

pub fn connect(session: &lila::Session, base_url: String, sri: String, pov: Arc<Mutex<super::Pov>>) {

    let url;
    {
        let pov = pov.lock().unwrap();
        let version = match pov.player.version {
            Some(v) => v,
            None => 0
        };
        url = Url::parse(&format!("ws://{}{}?sri={}&version={}", base_url, pov.url.socket.clone(), sri, version)).unwrap();
    }

    // TODO: this unwrap fails when url is wrong, port for example
    let mut request = websocket::Client::connect(url).unwrap();
    request.headers.set(Cookie::from_cookie_jar(&session.cjar));

    let response = request.send().unwrap();

    match response.validate() {
        Ok(()) => (),
        Err(e) => {
            error!("reponse validation error: {:?}", e);
            debug!("reponse status: {:?}, headers: {:?}", response.status, response.headers);
            return;
        }
    };

    //println!("Successfully connected");

    let (mut sender, mut receiver) = response.begin().split();

    let (tx, rx) = mpsc::channel();

    let tx_1 = tx.clone();

    let _send_loop = thread::spawn(move || {
        loop {
            let message: Message = match rx.recv() {
                Ok(m) => m,
                Err(e) => {
                    error!("Send loop, could not read next message: {:?}", e);
                    return;
                }
            };
            trace!("Transmit raw: {:?}", message);
            debug!("Transmit msg: {}",
                   &std::str::from_utf8(&message.payload).unwrap());
            match message.opcode {
                Type::Close => {
                    let _ = sender.send_message(&message);
                    return;
                }
                _ => (),
            }
            match sender.send_message(&message) {
                Ok(()) => (),
                Err(e) => {
                    error!("Send loop: could not send message: {:?}", e);
                    let _ = sender.send_message(&Message::close());
                    return;
                }
            }
        }
    });

    let pov_1 = pov.clone();
    let _receive_loop = thread::spawn(move || {

        let handle = |obj: json::Object| {
            let mut pov = pov_1.lock().unwrap();
            match obj.get("v") {
                Some(&Json::U64(v)) => {
                    pov.player.version = Some(v as i64);
                },
                _ => ()
            }
            match obj.get("t") {
                Some(&Json::String(ref t)) if t == "move" => {
                    let d = obj.get("d").unwrap().as_object().unwrap();
                    let fen = d.get("fen").unwrap().as_string().unwrap();
                    pov.game.fen = fen.to_string();
                    //cli::render_fen(fen);
                },
                Some(&Json::String(ref t)) if t == "clock" => {
                    let d = obj.get("d").unwrap().as_object().unwrap();
                    match pov.clock.as_mut() {
                        Some(clock) => {
                            clock.white = d.get("white").unwrap().as_f64().unwrap();
                            clock.black = d.get("black").unwrap().as_f64().unwrap();
                        },
                        None => ()
                    };
                },
                Some(&Json::String(ref t)) if t == "end" => {
                    let _ = tx_1.send(Message::close());
                    // exit
                },
                //Some(&Json::String(ref t)) => println!("unhandled: {:?}", obj),
                _ => ()
            }
        };

        for message in receiver.incoming_messages() {
            let message: Message = match message {
                Ok(m) => m,
                Err(e) => {
                    warn!("Receive loop error: {:?}", e);
                    let _ = tx_1.send(Message::close());
                    return;
                }
            };
            match message.opcode {
                Type::Close => {
                    let _ = tx_1.send(Message::close());
                    return;
                }
                Type::Ping => match tx_1.send(Message::pong(message.payload)) {
                    Ok(()) => (),
                    Err(e) => {
                        warn!("Could not send pong: {:?}", e);
                        return;
                    }
                },
                Type::Text => {
                    let str_payload = std::str::from_utf8(&message.payload).unwrap();
                    trace!("Received raw: {:?}", &message.payload);
                    trace!("Received str: {}", str_payload);
                    let json = Json::from_str(str_payload).unwrap();
                    debug!("Received obj: {:?}", json);
                    if json.is_object() {
                        let obj = json.as_object().unwrap();
                        let t = obj.get("t");
                        match t {
                            Some(&Json::String(ref t)) if t == "n" => { // pong
                            },
                            Some(&Json::String(ref t)) if t == "b" => { // batch
                                for item in obj.get("d").unwrap().as_array().unwrap().iter() {
                                   let obj = item.as_object().unwrap();
                                   handle(obj.clone());
                                }
                            }
                            _ => {
                                handle(obj.clone());
                            }
                        }
                    }
                }
                _ => debug!("Unhandled message: {:?}", message),
            }
        }
    });

    let tx_2 = tx.clone();

    thread::spawn(move || loop {
        thread::sleep(Duration::from_millis(1000));

        pov.lock().ok()
            .and_then(|p| p.player.version )
            .map(|v| PingPacket::new(v).to_message())
            .map(|p| tx_2.send(p).unwrap());
    });

    //let _ = send_loop.join();
    //let _ = receive_loop.join();
}

<commit_msg>more readable matchers<commit_after>extern crate websocket;

use std;
use std::sync::{Arc, Mutex};
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

use websocket::{Message, Sender, Receiver};
use websocket::message::Type;
use websocket::client::request::Url;

use hyper::header::{Cookie};

use rustc_serialize::json;
use rustc_serialize::json::Json;

use lila;

// making a move
// out {"t":"move","d":{"from":"e2","to":"e4","b":1}}
// in {t: "ack"}
// in {"v":1,"t":"move","d":{"uci":"e2e4","san":"e4","fen":"rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR","ply":1,"clock":{"white":172800,"black":172800},"dests":{"b8":"a6c6","g8":"f6h6","h7":"h6h5","d7":"d6d5","g7":"g6g5","c7":"c6c5","f7":"f6f5","b7":"b6b5","e7":"e6e5","a7":"a6a5"},"crazyhouse":{"pockets":[{},{}]}}}
// other player moved
// in {"v":2,"t":"move","d":{"uci":"g7g5","san":"g5","fen":"rnbqkbnr/pppppp1p/8/6p1/4P3/8/PPPP1PPP/RNBQKBNR","ply":2,"clock":{"white":172800,"black":172800},"dests":{"a2":"a3a4","g1":"f3h3e2","d1":"e2f3g4h5","e1":"e2","d2":"d3d4","b1":"a3c3","e4":"e5","f1":"e2d3c4b5a6","h2":"h3h4","b2":"b3b4","f2":"f3f4","c2":"c3c4","g2":"g3g4"},"crazyhouse":{"pockets":[{},{}]}}}

#[derive(RustcEncodable)]
struct PingPacket {
    t: String,
    v: i64
}

impl PingPacket {
    pub fn new(version: i64) -> PingPacket {
        PingPacket {
            t: "p".to_string(),
            v: version
        }
    }

    pub fn to_message(&self) -> Message<'static> {
        Message::text(json::encode(self).unwrap())
    }
}

#[allow(dead_code)]
#[derive(RustcEncodable)]
pub struct MovePacket {
    t: String,
    d: Dest,
}

#[allow(dead_code)]
#[derive(RustcEncodable)]
pub struct Dest {
    pub from: String,
    pub to: String,
    // pub: i8, // bool, but 0 or 1
}

pub fn connect(session: &lila::Session, base_url: String, sri: String, pov: Arc<Mutex<super::Pov>>) {

    let url;
    {
        let pov = pov.lock().unwrap();
        let version = match pov.player.version {
            Some(v) => v,
            None => 0
        };
        url = Url::parse(&format!("ws://{}{}?sri={}&version={}", base_url, pov.url.socket.clone(), sri, version)).unwrap();
    }

    // TODO: this unwrap fails when url is wrong, port for example
    let mut request = websocket::Client::connect(url).unwrap();
    request.headers.set(Cookie::from_cookie_jar(&session.cjar));

    let response = request.send().unwrap();

    match response.validate() {
        Ok(()) => (),
        Err(e) => {
            error!("reponse validation error: {:?}", e);
            debug!("reponse status: {:?}, headers: {:?}", response.status, response.headers);
            return;
        }
    };

    //println!("Successfully connected");

    let (mut sender, mut receiver) = response.begin().split();

    let (tx, rx) = mpsc::channel();

    let tx_1 = tx.clone();

    let _send_loop = thread::spawn(move || {
        loop {
            let message: Message = match rx.recv() {
                Ok(m) => m,
                Err(e) => {
                    error!("Send loop, could not read next message: {:?}", e);
                    return;
                }
            };
            trace!("Transmit raw: {:?}", message);
            debug!("Transmit msg: {}",
                   &std::str::from_utf8(&message.payload).unwrap());
            match message.opcode {
                Type::Close => {
                    let _ = sender.send_message(&message);
                    return;
                }
                _ => (),
            }
            match sender.send_message(&message) {
                Ok(()) => (),
                Err(e) => {
                    error!("Send loop: could not send message: {:?}", e);
                    let _ = sender.send_message(&Message::close());
                    return;
                }
            }
        }
    });

    let pov_1 = pov.clone();
    let _receive_loop = thread::spawn(move || {

        let handle = |obj: json::Object| {
            let mut pov = pov_1.lock().unwrap();
            match obj.get("v") {
                Some(&Json::U64(v)) => {
                    pov.player.version = Some(v as i64);
                },
                _ => ()
            }
            match obj.get("t").and_then(|t| t.as_string()) {
                Some("move") => {
                    let d = obj.get("d").unwrap().as_object().unwrap();
                    let fen = d.get("fen").unwrap().as_string().unwrap();
                    pov.game.fen = fen.to_string();
                    //cli::render_fen(fen);
                },
                Some("clock") => {
                    let d = obj.get("d").unwrap().as_object().unwrap();
                    match pov.clock.as_mut() {
                        Some(clock) => {
                            clock.white = d.get("white").unwrap().as_f64().unwrap();
                            clock.black = d.get("black").unwrap().as_f64().unwrap();
                        },
                        None => ()
                    };
                },
                Some("end") => {
                    let _ = tx_1.send(Message::close());
                    // exit
                },
                Some(ref t) => warn!("unhandled: {}, {:?}", t, obj),
                _ => ()
            }
        };

        for message in receiver.incoming_messages() {
            let message: Message = match message {
                Ok(m) => m,
                Err(e) => {
                    warn!("Receive loop error: {:?}", e);
                    let _ = tx_1.send(Message::close());
                    return;
                }
            };
            match message.opcode {
                Type::Close => {
                    let _ = tx_1.send(Message::close());
                    return;
                }
                Type::Ping => match tx_1.send(Message::pong(message.payload)) {
                    Ok(()) => (),
                    Err(e) => {
                        warn!("Could not send pong: {:?}", e);
                        return;
                    }
                },
                Type::Text => {
                    let str_payload = std::str::from_utf8(&message.payload).unwrap();
                    trace!("Received raw: {:?}", &message.payload);
                    trace!("Received str: {}", str_payload);
                    let json = Json::from_str(str_payload).unwrap();
                    debug!("Received obj: {:?}", json);
                    if json.is_object() {
                        let obj = json.as_object().unwrap();
                        match obj.get("t").and_then(|t| t.as_string()) {
                            Some("n") => { // pong
                                // track time between pings and these pongs for latency
                            },
                            Some("b") => { // batch
                                for item in obj.get("d").unwrap().as_array().unwrap().iter() {
                                   let obj = item.as_object().unwrap();
                                   handle(obj.clone());
                                }
                            }
                            _ => {
                                handle(obj.clone());
                            }
                        }
                    }
                }
                _ => debug!("Unhandled message: {:?}", message),
            }
        }
    });

    let tx_2 = tx.clone();

    thread::spawn(move || loop {
        thread::sleep(Duration::from_millis(2000));

        pov.lock().ok()
            .and_then(|p| p.player.version )
            .map(|v| PingPacket::new(v).to_message())
            .map(|p| tx_2.send(p).unwrap());
    });

    //let _ = send_loop.join();
    //let _ = receive_loop.join();
}

<|endoftext|>


<commit_before>use std::slice;
use std::io::MemReader;

use image;
use image::ImageResult;
use image::ImageDecoder;
use color;

use super::lzw::LZWReader;

macro_rules! io_try(
    ($e: expr) => (
        match $e {
            Ok(e) => e,
            Err(_) => return Err(image::IoError)
        }
    )
)

static IMAGEDESCRIPTOR: u8 = 0x2C;
static EXTENSION: u8 = 0x21;
static APPLICATION: u8 = 0xFF;
static GRAPHICCONTROL: u8 = 0xF9;
static COMMENT: u8 = 0xFE;
static TRAILER: u8 = 0x3B;

/// The Representation of a GIF decoder
pub struct GIFDecoder <R> {
    r: R,

    width: u16,
    height: u16,

    global_table: [(u8, u8, u8), ..256],
    local_table: Option<Vec<(u8, u8, u8)>>,

    delay: u16,
    image: Vec<u8>,

    global_backgroud_index: Option<u8>,
    local_transparent_index: Option<u8>,

    have_header: bool,
    decoded_rows: u32,
}

impl<R: Reader> GIFDecoder<R> {
    /// Create a new GIFDecoder from the Reader ```r```.
    /// This function takes ownership of the Reader.
    pub fn new(r: R) -> GIFDecoder<R> {
        GIFDecoder {
            r: r,

            width: 0,
            height: 0,

            global_table: [(0u8, 0u8, 0u8), ..256],
            local_table: None,

            delay: 0,
            image: Vec::new(),

            global_backgroud_index: None,
            local_transparent_index: None,

            have_header: false,
            decoded_rows: 0,
        }
    }

    ///Returns the display delay in 100th's of a second for the currently
    ///decoded image.
    pub fn delay(&mut self) -> ImageResult<u16> {

        let _ = try!(self.read_metadata());

        Ok(self.delay)
    }

    fn read_header(&mut self) -> ImageResult<()> {
        let signature = io_try!(self.r.read_exact(3));
        let version   = io_try!(self.r.read_exact(3));

        if signature.as_slice() != "GIF".as_bytes() {
            Err(image::FormatError)
        } else if version.as_slice() != "87a".as_bytes() &&
            version.as_slice() != "89a".as_bytes() {
            Err(image::UnsupportedError)
        } else {
            Ok(())
        }
    }

    fn read_block(&mut self) -> ImageResult<Vec<u8>> {
        let size = io_try!(self.r.read_u8());
        Ok(io_try!(self.r.read_exact(size as uint)))
    }

    fn read_image_data(&mut self) -> ImageResult<Vec<u8>> {
        let minimum_code_size = io_try!(self.r.read_u8());

        if minimum_code_size > 8 {
            return Err(image::FormatError)
        }

        let mut data = Vec::new();
        loop {
            let b = io_try!(self.read_block());

            if b.len() == 0 {
                break
            }

            data = data + b;
        }

        let m = MemReader::new(data);
        let mut lzw = LZWReader::new(m, minimum_code_size);
        let b = lzw.read_to_end().unwrap();

        Ok(b)
    }

    fn read_image_descriptor(&mut self) -> ImageResult<()> {
        let image_left   = io_try!(self.r.read_le_u16());
        let image_top    = io_try!(self.r.read_le_u16());
        let image_width  = io_try!(self.r.read_le_u16());
        let image_height = io_try!(self.r.read_le_u16());

        let fields = io_try!(self.r.read_u8());

        let local_table = fields & 80 != 0;
        let interlace   = fields & 40 != 0;
        let table_size  = fields & 7;

        if interlace {
            return Err(image::UnsupportedError)
        }

        if local_table {
            let n   = 1 << (table_size + 1) as uint;
            let buf = io_try!(self.r.read_exact(3 * n));
            let mut b = Vec::from_elem(n, (0u8, 0u8, 0u8));

            for (i, rgb) in buf.as_slice().chunks(3).enumerate() {
                b.as_mut_slice()[i] = (rgb[0], rgb[1], rgb[2]);
            }

            self.local_table = Some(b);
        }

        let indices = try!(self.read_image_data());

        {

            let trans_index = if self.local_transparent_index.is_some() {
                self.local_transparent_index
            } else {
                self.global_backgroud_index
            };

            let table = if self.local_table.is_some() {
                self.local_table.get_ref().as_slice()
            } else {
                self.global_table.as_slice()
            };

            expand_image(
                table,
                indices.as_slice(),
                image_top as uint,
                image_left as uint,
                image_width as uint,
                image_height as uint,
                self.width as uint * 3,
                trans_index,
                self.image.as_mut_slice()
            );
        }

        self.local_table = None;
        self.local_transparent_index = None;

        Ok(())
    }

    fn read_extension(&mut self) -> ImageResult<()> {
        let identifier = io_try!(self.r.read_u8());

        match identifier {
            APPLICATION    => try!(self.read_application_extension()),
            GRAPHICCONTROL => try!(self.read_graphic_control_extension()),
            COMMENT 	   => try!(self.read_comment_extension()),
            _              => return Err(image::UnsupportedError)
        }

        Ok(())
    }

    fn read_comment_extension(&mut self) -> ImageResult<()> {
        loop {
            let b = io_try!(self.read_block());

            if b.len() == 0 {
                break
            }
        }

        Ok(())
    }

    fn read_graphic_control_extension(&mut self) -> ImageResult<()> {
        let size   = io_try!(self.r.read_u8());
        assert!(size == 4);

        let fields = io_try!(self.r.read_u8());
        self.delay = io_try!(self.r.read_le_u16());
        let trans  = io_try!(self.r.read_u8());

        if fields & 1 != 0 {
            self.local_transparent_index = Some(trans);
        }

        let _disposal = (fields & 0x1C) >> 2;
        let _term = io_try!(self.r.read_u8());

        Ok(())
    }

    fn read_application_extension(&mut self) -> ImageResult<()> {
        let size = io_try!(self.r.read_u8());
        let _ = io_try!(self.r.read_exact(size as uint));

        loop {
            let b = io_try!(self.read_block());

            if b.len() == 0 {
                break
            }
        }

        Ok(())
    }

    fn read_logical_screen_descriptor(&mut self) -> ImageResult<()> {
        self.width  = io_try!(self.r.read_le_u16());
        self.height = io_try!(self.r.read_le_u16());
        self.image  = Vec::from_elem(self.width as uint * self.height as uint * 3, 0u8);

        let fields = io_try!(self.r.read_u8());

        let global_table = fields & 0x80 != 0;

        let entries = if global_table {
            1 << ((fields & 7) + 1) as uint
        } else {
            0u
        };

        if global_table {
        let b = io_try!(self.r.read_u8());
            self.global_backgroud_index = Some(b);
        }

        let _aspect_ratio = io_try!(self.r.read_u8());

        let buf = io_try!(self.r.read_exact(3 * entries));

        for (i, rgb) in buf.as_slice().chunks(3).enumerate() {
            self.global_table.as_mut_slice()[i] = (rgb[0], rgb[1], rgb[2]);
        }

        Ok(())
    }

    fn read_metadata(&mut self) -> ImageResult<()> {
        if !self.have_header {
            let _ = try!(self.read_header());
            let _ = try!(self.read_logical_screen_descriptor());
            self.have_header = true;
        }

        Ok(())
    }
}

impl<R: Reader> ImageDecoder for GIFDecoder<R> {
    fn dimensions(&mut self) -> ImageResult<(u32, u32)> {
        let _ = try!(self.read_metadata());
        Ok((self.width as u32, self.height as u32))
    }

    fn colortype(&mut self) -> ImageResult<color::ColorType> {
        let _ = try!(self.read_metadata());
        Ok(color::RGB(8))
    }

    fn row_len(&mut self) -> ImageResult<uint> {
        let _ = try!(self.read_metadata());
        Ok(3 * self.width as uint)
    }

    fn read_scanline(&mut self, buf: &mut [u8]) -> ImageResult<u32> {
        let _ = try!(self.read_metadata());
        if self.decoded_rows == self.height as u32 || self.image.len() == 0 {
            let _ = try!(self.read_image());
        }

        let rlen  = buf.len();
        let slice = self.image.slice(self.decoded_rows as uint * rlen,
        self.decoded_rows as uint * rlen + rlen);

        slice::bytes::copy_memory(buf, slice);
        self.decoded_rows += 1;

        Ok(self.decoded_rows)
    }

    fn read_image(&mut self) -> ImageResult<Vec<u8>> {
        let _ = try!(self.read_metadata());
        loop {
            let block = io_try!(self.r.read_u8());

            match block {
                EXTENSION => try!(self.read_extension()),
                IMAGEDESCRIPTOR => {
                    let _ = try!(self.read_image_descriptor());
                    return Ok(self.image.clone())
                }
                TRAILER => break,
                _       => return Err(image::UnsupportedError)
            }
        }

        Err(image::ImageEnd)
    }
}

fn expand_image(palete: &[(u8, u8, u8)],
                indices: &[u8],
                y0: uint,
                x0: uint,
                width: uint,
                height: uint,
                stride: uint,
                trans_index: Option<u8>,
                image: &mut [u8]) {

    for y in range(0, height) {
        for x in range(0, width) {
            let index = indices[y * width + x];

            if trans_index == Some(index) {
                continue
            }

            let (r, g, b) = palete[index as uint];

            image[(y0 + y) * stride + x0 * 3 + x * 3 + 0] = r;
            image[(y0 + y) * stride + x0 * 3 + x * 3 + 1] = g;
            image[(y0 + y) * stride + x0 * 3 + x * 3 + 2] = b;
        }
    }
}<commit_msg>indentation fix<commit_after>use std::slice;
use std::io::MemReader;

use image;
use image::ImageResult;
use image::ImageDecoder;
use color;

use super::lzw::LZWReader;

macro_rules! io_try(
    ($e: expr) => (
        match $e {
            Ok(e) => e,
            Err(_) => return Err(image::IoError)
        }
    )
)

static IMAGEDESCRIPTOR: u8 = 0x2C;
static EXTENSION: u8 = 0x21;
static APPLICATION: u8 = 0xFF;
static GRAPHICCONTROL: u8 = 0xF9;
static COMMENT: u8 = 0xFE;
static TRAILER: u8 = 0x3B;

/// The Representation of a GIF decoder
pub struct GIFDecoder <R> {
    r: R,

    width: u16,
    height: u16,

    global_table: [(u8, u8, u8), ..256],
    local_table: Option<Vec<(u8, u8, u8)>>,

    delay: u16,
    image: Vec<u8>,

    global_backgroud_index: Option<u8>,
    local_transparent_index: Option<u8>,

    have_header: bool,
    decoded_rows: u32,
}

impl<R: Reader> GIFDecoder<R> {
    /// Create a new GIFDecoder from the Reader ```r```.
    /// This function takes ownership of the Reader.
    pub fn new(r: R) -> GIFDecoder<R> {
        GIFDecoder {
            r: r,

            width: 0,
            height: 0,

            global_table: [(0u8, 0u8, 0u8), ..256],
            local_table: None,

            delay: 0,
            image: Vec::new(),

            global_backgroud_index: None,
            local_transparent_index: None,

            have_header: false,
            decoded_rows: 0,
        }
    }

    ///Returns the display delay in 100th's of a second for the currently
    ///decoded image.
    pub fn delay(&mut self) -> ImageResult<u16> {

        let _ = try!(self.read_metadata());

        Ok(self.delay)
    }

    fn read_header(&mut self) -> ImageResult<()> {
        let signature = io_try!(self.r.read_exact(3));
        let version   = io_try!(self.r.read_exact(3));

        if signature.as_slice() != "GIF".as_bytes() {
            Err(image::FormatError)
        } else if version.as_slice() != "87a".as_bytes() &&
                  version.as_slice() != "89a".as_bytes() {
            Err(image::UnsupportedError)
        } else {
            Ok(())
        }
    }

    fn read_block(&mut self) -> ImageResult<Vec<u8>> {
        let size = io_try!(self.r.read_u8());
        Ok(io_try!(self.r.read_exact(size as uint)))
    }

    fn read_image_data(&mut self) -> ImageResult<Vec<u8>> {
        let minimum_code_size = io_try!(self.r.read_u8());

        if minimum_code_size > 8 {
            return Err(image::FormatError)
        }

        let mut data = Vec::new();
        loop {
            let b = io_try!(self.read_block());

            if b.len() == 0 {
                break
            }

            data = data + b;
        }

        let m = MemReader::new(data);
        let mut lzw = LZWReader::new(m, minimum_code_size);
        let b = lzw.read_to_end().unwrap();

        Ok(b)
    }

    fn read_image_descriptor(&mut self) -> ImageResult<()> {
        let image_left   = io_try!(self.r.read_le_u16());
        let image_top    = io_try!(self.r.read_le_u16());
        let image_width  = io_try!(self.r.read_le_u16());
        let image_height = io_try!(self.r.read_le_u16());

        let fields = io_try!(self.r.read_u8());

        let local_table = fields & 80 != 0;
        let interlace   = fields & 40 != 0;
        let table_size  = fields & 7;

        if interlace {
            return Err(image::UnsupportedError)
        }

        if local_table {
            let n   = 1 << (table_size + 1) as uint;
            let buf = io_try!(self.r.read_exact(3 * n));
            let mut b = Vec::from_elem(n, (0u8, 0u8, 0u8));

            for (i, rgb) in buf.as_slice().chunks(3).enumerate() {
                b.as_mut_slice()[i] = (rgb[0], rgb[1], rgb[2]);
            }

            self.local_table = Some(b);
        }

        let indices = try!(self.read_image_data());

        {

            let trans_index = if self.local_transparent_index.is_some() {
                self.local_transparent_index
            } else {
                self.global_backgroud_index
            };

            let table = if self.local_table.is_some() {
                self.local_table.get_ref().as_slice()
            } else {
                self.global_table.as_slice()
            };

            expand_image(
                table,
                indices.as_slice(),
                image_top as uint,
                image_left as uint,
                image_width as uint,
                image_height as uint,
                self.width as uint * 3,
                trans_index,
                self.image.as_mut_slice()
            );
        }

        self.local_table = None;
        self.local_transparent_index = None;

        Ok(())
    }

    fn read_extension(&mut self) -> ImageResult<()> {
        let identifier = io_try!(self.r.read_u8());

        match identifier {
            APPLICATION    => try!(self.read_application_extension()),
            GRAPHICCONTROL => try!(self.read_graphic_control_extension()),
            COMMENT 	   => try!(self.read_comment_extension()),
            _              => return Err(image::UnsupportedError)
        }

        Ok(())
    }

    fn read_comment_extension(&mut self) -> ImageResult<()> {
        loop {
            let b = io_try!(self.read_block());

            if b.len() == 0 {
                break
            }
        }

        Ok(())
    }

    fn read_graphic_control_extension(&mut self) -> ImageResult<()> {
        let size   = io_try!(self.r.read_u8());
        assert!(size == 4);

        let fields = io_try!(self.r.read_u8());
        self.delay = io_try!(self.r.read_le_u16());
        let trans  = io_try!(self.r.read_u8());

        if fields & 1 != 0 {
            self.local_transparent_index = Some(trans);
        }

        let _disposal = (fields & 0x1C) >> 2;
        let _term = io_try!(self.r.read_u8());

        Ok(())
    }

    fn read_application_extension(&mut self) -> ImageResult<()> {
        let size = io_try!(self.r.read_u8());
        let _ = io_try!(self.r.read_exact(size as uint));

        loop {
            let b = io_try!(self.read_block());

            if b.len() == 0 {
                break
            }
        }

        Ok(())
    }

    fn read_logical_screen_descriptor(&mut self) -> ImageResult<()> {
        self.width  = io_try!(self.r.read_le_u16());
        self.height = io_try!(self.r.read_le_u16());
        self.image  = Vec::from_elem(self.width as uint * self.height as uint * 3, 0u8);

        let fields = io_try!(self.r.read_u8());

        let global_table = fields & 0x80 != 0;

        let entries = if global_table {
            1 << ((fields & 7) + 1) as uint
        } else {
            0u
        };

        if global_table {
        let b = io_try!(self.r.read_u8());
            self.global_backgroud_index = Some(b);
        }

        let _aspect_ratio = io_try!(self.r.read_u8());

        let buf = io_try!(self.r.read_exact(3 * entries));

        for (i, rgb) in buf.as_slice().chunks(3).enumerate() {
            self.global_table.as_mut_slice()[i] = (rgb[0], rgb[1], rgb[2]);
        }

        Ok(())
    }

    fn read_metadata(&mut self) -> ImageResult<()> {
        if !self.have_header {
            let _ = try!(self.read_header());
            let _ = try!(self.read_logical_screen_descriptor());
            self.have_header = true;
        }

        Ok(())
    }
}

impl<R: Reader> ImageDecoder for GIFDecoder<R> {
    fn dimensions(&mut self) -> ImageResult<(u32, u32)> {
        let _ = try!(self.read_metadata());
        Ok((self.width as u32, self.height as u32))
    }

    fn colortype(&mut self) -> ImageResult<color::ColorType> {
        let _ = try!(self.read_metadata());
        Ok(color::RGB(8))
    }

    fn row_len(&mut self) -> ImageResult<uint> {
        let _ = try!(self.read_metadata());
        Ok(3 * self.width as uint)
    }

    fn read_scanline(&mut self, buf: &mut [u8]) -> ImageResult<u32> {
        let _ = try!(self.read_metadata());
        if self.decoded_rows == self.height as u32 || self.image.len() == 0 {
            let _ = try!(self.read_image());
        }

        let rlen  = buf.len();
        let slice = self.image.slice(self.decoded_rows as uint * rlen,
        self.decoded_rows as uint * rlen + rlen);

        slice::bytes::copy_memory(buf, slice);
        self.decoded_rows += 1;

        Ok(self.decoded_rows)
    }

    fn read_image(&mut self) -> ImageResult<Vec<u8>> {
        let _ = try!(self.read_metadata());
        loop {
            let block = io_try!(self.r.read_u8());

            match block {
                EXTENSION => try!(self.read_extension()),
                IMAGEDESCRIPTOR => {
                    let _ = try!(self.read_image_descriptor());
                    return Ok(self.image.clone())
                }
                TRAILER => break,
                _       => return Err(image::UnsupportedError)
            }
        }

        Err(image::ImageEnd)
    }
}

fn expand_image(palete: &[(u8, u8, u8)],
                indices: &[u8],
                y0: uint,
                x0: uint,
                width: uint,
                height: uint,
                stride: uint,
                trans_index: Option<u8>,
                image: &mut [u8]) {

    for y in range(0, height) {
        for x in range(0, width) {
            let index = indices[y * width + x];

            if trans_index == Some(index) {
                continue
            }

            let (r, g, b) = palete[index as uint];

            image[(y0 + y) * stride + x0 * 3 + x * 3 + 0] = r;
            image[(y0 + y) * stride + x0 * 3 + x * 3 + 1] = g;
            image[(y0 + y) * stride + x0 * 3 + x * 3 + 2] = b;
        }
    }
}<|endoftext|>


<commit_before>
use std::str::CharIndices;
use std::iter::Peekable;

#[derive(PartialEq, Debug)]
pub enum Token<'a> {
  Eof(usize, usize),
  Punctuator(Punctuator, usize),
  Name(&'a str, usize, usize),
  IntValue(&'a str, usize, usize),
  FloatValue(&'a str, usize, usize),
  StringValue(&'a str, usize, usize),
}

#[derive(PartialEq, Debug)]
pub enum Punctuator {
  Bang,
  Dollar,
  LeftParen,
  RightParen,
  Spread(usize),
  Colon,
  Equals,
  At,
  LeftBracket,
  RightBracket,
  LeftBrace,
  RightBrace,
  Pipe,
}

macro_rules! take {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_taken = false;
    if let Some(&(p, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            $lexer.iter.next();
            $lexer.hi = p;
            is_taken = true;
          }
        )*
        _ => {}
      }
    }
    is_taken
  });
}

macro_rules! take_while {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_taken = false;
    while let Some(&(p, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            $lexer.iter.next();
            is_taken = true;
          }
        )*
        _ => {
          $lexer.hi = p;
          break;
        }
      }
    }
    is_taken
  });
}

macro_rules! take_while_not {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_taken = false;
    while let Some(&(p, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            $lexer.hi = p;
            break;
          }
        )*
        _ => {
            $lexer.iter.next();
            is_taken = true;
        }
      }
    }
    is_taken
  });
}

macro_rules! peek {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_match = false;
    if let Some(&(_, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            is_match = true;
          }
        )*
        _ => {}
      }
    }
    is_match
  });
}

macro_rules! take_eof {
  ($lexer: ident) => ({
    if $lexer.iter.peek().is_none() {
      $lexer.hi = $lexer.input_len;
      true
    } else {
      false
    }
  });
}

pub struct Lexer<'a> {
  input: &'a str,
  input_len: usize,
  iter: Peekable<CharIndices<'a>>,
  is_eof: bool,
  lo: usize,
  hi: usize,
}

impl<'a> Lexer<'a> {
  pub fn new(input: &'a str) -> Lexer<'a> {
    Lexer {
      input: input,
      input_len: input.len(),
      iter: input.char_indices().peekable(),
      is_eof: false,
      lo: 0,
      hi: 0,
    }
  }
}

fn skip_ignored_token(lexer: &mut Lexer) {
  loop {
    if take!(lexer, '#') {
      take_while_not!(lexer, '\r' | '\n');
    }
    if !take_while!(lexer, '\u{feff}' | ' ' | '\t' | '\r' | '\n' | ',') {
      break;
    }
  }
}

fn scan_spread(lexer: &mut Lexer) -> bool {
  if take!(lexer, '.') {
    if take!(lexer, '.') {
      if take!(lexer, '.') {
        return true;
      }
    }
  }
  return false;
}

fn scan_name(lexer: &mut Lexer) {
  take_while!(lexer, '_' | 'a'...'z' | 'A'...'Z' | '0'...'9');
  take_eof!(lexer);
}

// Return the raw string without unescape character
fn scan_string(lexer: &mut Lexer) -> (bool, bool) {
  let mut is_bad_escape = false;
  let mut is_terminated = false;
  if take!(lexer, '"') {
    lexer.lo = lexer.lo + 1;
  }
  loop {
    if take!(lexer, '\\') {
      if !take!(lexer, '\\' | '"' | 'b' | 'f' | 'n' | 'r' | 't' | '/' | 'u') {
        is_bad_escape = true;
        break;
      }
    }
    take_while_not!(lexer, '"' | '\\');
    if take!(lexer, '"') {
      is_terminated = true;
      break;
    }
  }
  (is_terminated, is_bad_escape)
}

// Int:   (+|-)?(0|[1-9][0-9]*)
// Float: (+|-)?(0|[1-9][0-9]*)(\.[0-9]+)?((E|e)(+|-)?[0-9]+)?
fn scan_number(lexer: &mut Lexer) -> (bool, bool) {
  let mut is_float = false;
  take!(lexer, '+' | '-');
  // Integer part
  if take!(lexer, '1'...'9') {
    take_while!(lexer, '0'...'9');
    if take!(lexer, ' ' | '\t' | '\r' | '\n' | ',') || take_eof!(lexer) {
      return (true, is_float);
    }
  } else if take!(lexer, '0') {
    if take!(lexer, ' ' | '\t' | '\r' | '\n' | ',') || take_eof!(lexer) {
      return (true, is_float);
    }
  }
  // Fractional part
  if take!(lexer, '.') {
    if !take_while!(lexer, '0'...'9') {
      return (false, is_float);
    }
    is_float = true;
  }
  // Exponent part
  if !is_float && peek!(lexer, 'E' | 'e') {
    return (false, is_float);
  }
  if take!(lexer, 'E' | 'e') {
    if take!(lexer, '+' | '-') {
      if !take_while!(lexer, '0'...'9') {
        return (false, is_float);
      }
    } else {
      take_while!(lexer, '0'...'9');
    }
  }

  if take!(lexer, ' ' | '\t' | '\r' | '\n' | ',') || take_eof!(lexer) {
    return (true, is_float);
  }
  return (false, is_float);
}

impl<'a> Iterator for Lexer<'a> {
  type Item = Result<Token<'a>, &'a str>;
  fn next(&mut self) -> Option<Result<Token<'a>, &'a str>> {
    if !self.is_eof && take_eof!(self) {
      self.is_eof = true;
      return Some(Ok(Token::Eof(self.lo, self.hi)));
    }
    if self.is_eof {
      return None;
    }
    skip_ignored_token(self);

    let mut item = None;
    if let Some(&(p, c)) = self.iter.peek() {
      self.lo = p;
      self.hi = p;
      item = match c {
        '!' => {
          self.iter.next();
          Some(Ok(Token::Bang(self.lo, self.hi)))
        }
        '$' => {
          self.iter.next();
          Some(Ok(Token::Dollar(self.lo, self.hi)))
        }
        '(' => {
          self.iter.next();
          Some(Ok(Token::LeftParen(self.lo, self.hi)))
        }
        ')' => {
          self.iter.next();
          Some(Ok(Token::RightParen(self.lo, self.hi)))
        }
        ':' => {
          self.iter.next();
          Some(Ok(Token::Colon(self.lo, self.hi)))
        }
        '=' => {
          self.iter.next();
          Some(Ok(Token::Equals(self.lo, self.hi)))
        }
        '@' => {
          self.iter.next();
          Some(Ok(Token::At(self.lo, self.hi)))
        }
        '[' => {
          self.iter.next();
          Some(Ok(Token::LeftBracket(self.lo, self.hi)))
        }
        ']' => {
          self.iter.next();
          Some(Ok(Token::RightBracket(self.lo, self.hi)))
        }
        '{' => {
          self.iter.next();
          Some(Ok(Token::LeftBrace(self.lo, self.hi)))
        }
        '}' => {
          self.iter.next();
          Some(Ok(Token::RightBrace(self.lo, self.hi)))
        }
        '|' => {
          self.iter.next();
          Some(Ok(Token::Pipe(self.lo, self.hi)))
        }
        '.' => {
          if scan_spread(self) {
            Some(Ok(Token::Spread(self.lo, self.hi)))
          } else {
            Some(Err("Unexpected character."))
          }
        }
        '_' | 'a'...'z' | 'A'...'Z' => {
          scan_name(self);
          Some(Ok(Token::Name(self.lo, self.hi, &self.input[self.lo..self.hi])))
        }
        '-' | '0'...'9' => {
          match scan_number(self) {
            (false, false) => Some(Err("Invalid integer number.")),
            (false, true) => Some(Err("Invalid float number.")),
            (true, false) => Some(Ok(Token::Int(self.lo, self.hi, &self.input[self.lo..self.hi]))),
            (true, true) => Some(Ok(Token::Float(self.lo, self.hi, &self.input[self.lo..self.hi]))),
          }
        }
        '"' => {
          match scan_string(self) {
            (false, _) => Some(Err("Unterminated string.")),
            (_, true) => Some(Err("Bad character escape sequence.")),
            _ => Some(Ok(Token::String(self.lo, self.hi, &self.input[self.lo..self.hi]))),
          }
        }
        _ => Some(Err("Unexpected character.")),
      }
    }
    item
  }
}

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

  fn test_next_token(lexer: &mut Lexer, expected: Token) {
    let next = lexer.next();
    assert_eq!(Some(Ok(expected)), next);
  }

  fn test_with_lex(input: &str, expeced: Token) {
    let mut lexer = Lexer::new(&input);
    test_next_token(&mut lexer, expeced);
  }

  fn test_str(input: &str, expeced: &str) {
    let len = expeced.len();
    test_with_lex(input, Token::String(1, len + 1, expeced))
  }

  #[test]
  fn test_string() {
    test_str(r#""simple""#, r#"simple"#);
    test_str(r#"" white space ""#, r#" white space "#);
    test_str(r#""quote \"""#, r#"quote \""#);
    test_str(r#""slashes \\ \/""#, r#"slashes \\ \/"#);
    test_str(r#""unicode \u1234\u5678\u90AB\uCDEF""#,
             r#"unicode \u1234\u5678\u90AB\uCDEF"#);
  }

  #[test]
  fn test_name() {
    let mut lexer = Lexer::new("     name1    name2   \"simple\" \"  white space   \" other_name");
    test_next_token(&mut lexer, Token::Name(5, 10,"name1"));
    test_next_token(&mut lexer, Token::Name(14,19,"name2"));
    test_next_token(&mut lexer, Token::String(23,29,"simple"));
    test_next_token(&mut lexer, Token::String(32,48,"  white space   "));
    test_next_token(&mut lexer, Token::Name(50,60,"other_name"));
    test_next_token(&mut lexer, Token::Eof(50,60));
    assert_eq!(None, lexer.next());
  }

  #[test]
  fn test_number() {
    let mut lexer = Lexer::new("-9 0 9 -0 -9 1234 -1234 0.0 -0.0 1.0 -1.012 -0.101 1.0e2 -1.0E2 \
                                0.00e-002 -0.00E+002 9.1E+0");
    test_next_token(&mut lexer, Token::Int(0,2,    "-9"));
    test_next_token(&mut lexer, Token::Int(3,4,    "0"));
    test_next_token(&mut lexer, Token::Int(5,6,    "9"));
    test_next_token(&mut lexer, Token::Int(7,9,    "-0"));
    test_next_token(&mut lexer, Token::Int(10,12,  "-9"));
    test_next_token(&mut lexer, Token::Int(13,17,  "1234"));
    test_next_token(&mut lexer, Token::Int(18,23,  "-1234"));
    test_next_token(&mut lexer, Token::Float(24,27,"0.0"));
    test_next_token(&mut lexer, Token::Float(28,32,"-0.0"));
    test_next_token(&mut lexer, Token::Float(33,36,"1.0"));
    test_next_token(&mut lexer, Token::Float(37,43,"-1.012"));
    test_next_token(&mut lexer, Token::Float(44,50,"-0.101"));
    test_next_token(&mut lexer, Token::Float(51,56,"1.0e2"));
    test_next_token(&mut lexer, Token::Float(57,63,"-1.0E2"));
    test_next_token(&mut lexer, Token::Float(64,73,"0.00e-002"));
    test_next_token(&mut lexer, Token::Float(74,84,"-0.00E+002"));
    test_next_token(&mut lexer, Token::Float(85,91,"9.1E+0"));
    test_next_token(&mut lexer, Token::Eof(85,91));
    assert_eq!(None, lexer.next());
  }

  #[test]
  fn test_symbol() {
    let mut lexer = Lexer::new("@ !  :$ =    [  {   (|] } )      ...");
    test_next_token(&mut lexer, Token::At(0,0));
    test_next_token(&mut lexer, Token::Bang(2,2));
    test_next_token(&mut lexer, Token::Colon(5,5));
    test_next_token(&mut lexer, Token::Dollar(6,6));
    test_next_token(&mut lexer, Token::Equals(8,8));
    test_next_token(&mut lexer, Token::LeftBracket(13,13));
    test_next_token(&mut lexer, Token::LeftBrace(16,16));
    test_next_token(&mut lexer, Token::LeftParen(20,20));
    test_next_token(&mut lexer, Token::Pipe(21,21));
    test_next_token(&mut lexer, Token::RightBracket(22,22));
    test_next_token(&mut lexer, Token::RightBrace(24,24));
    test_next_token(&mut lexer, Token::RightParen(26,26));
    test_next_token(&mut lexer, Token::Spread(33,35));
    test_next_token(&mut lexer, Token::Eof(33,36));
    assert_eq!(None, lexer.next());
  }
}
<commit_msg>feat: use new Punctuator enum, and fix tests<commit_after>
use std::str::CharIndices;
use std::iter::Peekable;

#[derive(PartialEq, Debug)]
pub enum Token<'a> {
  Eof(usize, usize),
  Punctuator(Punctuator, usize),
  Name(&'a str, usize, usize),
  IntValue(&'a str, usize, usize),
  FloatValue(&'a str, usize, usize),
  StringValue(&'a str, usize, usize),
}

#[derive(PartialEq, Debug)]
pub enum Punctuator {
  Bang,
  Dollar,
  LeftParen,
  RightParen,
  Spread(usize),
  Colon,
  Equals,
  At,
  LeftBracket,
  RightBracket,
  LeftBrace,
  RightBrace,
  Pipe,
}

macro_rules! take {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_taken = false;
    if let Some(&(p, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            $lexer.iter.next();
            $lexer.hi = p;
            is_taken = true;
          }
        )*
        _ => {}
      }
    }
    is_taken
  });
}

macro_rules! take_while {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_taken = false;
    while let Some(&(p, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            $lexer.iter.next();
            is_taken = true;
          }
        )*
        _ => {
          $lexer.hi = p;
          break;
        }
      }
    }
    is_taken
  });
}

macro_rules! take_while_not {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_taken = false;
    while let Some(&(p, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            $lexer.hi = p;
            break;
          }
        )*
        _ => {
            $lexer.iter.next();
            is_taken = true;
        }
      }
    }
    is_taken
  });
}

macro_rules! peek {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_match = false;
    if let Some(&(_, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            is_match = true;
          }
        )*
        _ => {}
      }
    }
    is_match
  });
}

macro_rules! take_eof {
  ($lexer: ident) => ({
    if $lexer.iter.peek().is_none() {
      $lexer.hi = $lexer.input_len;
      true
    } else {
      false
    }
  });
}

pub struct Lexer<'a> {
  input: &'a str,
  input_len: usize,
  iter: Peekable<CharIndices<'a>>,
  is_eof: bool,
  lo: usize,
  hi: usize,
}

impl<'a> Lexer<'a> {
  pub fn new(input: &'a str) -> Lexer<'a> {
    Lexer {
      input: input,
      input_len: input.len(),
      iter: input.char_indices().peekable(),
      is_eof: false,
      lo: 0,
      hi: 0,
    }
  }
}

fn skip_ignored_token(lexer: &mut Lexer) {
  loop {
    if take!(lexer, '#') {
      take_while_not!(lexer, '\r' | '\n');
    }
    if !take_while!(lexer, '\u{feff}' | ' ' | '\t' | '\r' | '\n' | ',') {
      break;
    }
  }
}

fn scan_spread(lexer: &mut Lexer) -> bool {
  if take!(lexer, '.') {
    if take!(lexer, '.') {
      if take!(lexer, '.') {
        return true;
      }
    }
  }
  return false;
}

fn scan_name(lexer: &mut Lexer) {
  take_while!(lexer, '_' | 'a'...'z' | 'A'...'Z' | '0'...'9');
  take_eof!(lexer);
}

// Return the raw string without unescape character
fn scan_string(lexer: &mut Lexer) -> (bool, bool) {
  let mut is_bad_escape = false;
  let mut is_terminated = false;
  if take!(lexer, '"') {
    lexer.lo = lexer.lo + 1;
  }
  loop {
    if take!(lexer, '\\') {
      if !take!(lexer, '\\' | '"' | 'b' | 'f' | 'n' | 'r' | 't' | '/' | 'u') {
        is_bad_escape = true;
        break;
      }
    }
    take_while_not!(lexer, '"' | '\\');
    if take!(lexer, '"') {
      is_terminated = true;
      break;
    }
  }
  (is_terminated, is_bad_escape)
}

// IntValue:   (+|-)?(0|[1-9][0-9]*)
// FloatValue: (+|-)?(0|[1-9][0-9]*)(\.[0-9]+)?((E|e)(+|-)?[0-9]+)?
fn scan_number(lexer: &mut Lexer) -> (bool, bool) {
  let mut is_float = false;
  take!(lexer, '+' | '-');
  // IntValueeger part
  if take!(lexer, '1'...'9') {
    take_while!(lexer, '0'...'9');
    if take!(lexer, ' ' | '\t' | '\r' | '\n' | ',') || take_eof!(lexer) {
      return (true, is_float);
    }
  } else if take!(lexer, '0') {
    if take!(lexer, ' ' | '\t' | '\r' | '\n' | ',') || take_eof!(lexer) {
      return (true, is_float);
    }
  }
  // Fractional part
  if take!(lexer, '.') {
    if !take_while!(lexer, '0'...'9') {
      return (false, is_float);
    }
    is_float = true;
  }
  // Exponent part
  if !is_float && peek!(lexer, 'E' | 'e') {
    return (false, is_float);
  }
  if take!(lexer, 'E' | 'e') {
    if take!(lexer, '+' | '-') {
      if !take_while!(lexer, '0'...'9') {
        return (false, is_float);
      }
    } else {
      take_while!(lexer, '0'...'9');
    }
  }

  if take!(lexer, ' ' | '\t' | '\r' | '\n' | ',') || take_eof!(lexer) {
    return (true, is_float);
  }
  return (false, is_float);
}

impl<'a> Iterator for Lexer<'a> {
  type Item = Result<Token<'a>, &'a str>;
  fn next(&mut self) -> Option<Result<Token<'a>, &'a str>> {
    use self::Token::*;
    use self::Punctuator::*;

    if !self.is_eof && take_eof!(self) {
      self.is_eof = true;
      return Some(Ok(Token::Eof(self.lo, self.hi)));
    }
    if self.is_eof {
      return None;
    }
    skip_ignored_token(self);

    let mut item = None;
    if let Some(&(p, c)) = self.iter.peek() {
      self.lo = p;
      self.hi = p;
      item = match c {
        '!' => {
          self.iter.next();
          Some(Ok(Punctuator(Bang, self.lo)))
        }
        '$' => {
          self.iter.next();
          Some(Ok(Punctuator(Dollar, self.lo)))
        }
        '(' => {
          self.iter.next();
          Some(Ok(Punctuator(LeftParen, self.lo)))
        }
        ')' => {
          self.iter.next();
          Some(Ok(Punctuator(RightParen, self.lo)))
        }
        ':' => {
          self.iter.next();
          Some(Ok(Punctuator(Colon, self.lo)))
        }
        '=' => {
          self.iter.next();
          Some(Ok(Punctuator(Equals, self.lo)))
        }
        '@' => {
          self.iter.next();
          Some(Ok(Punctuator(At, self.lo)))
        }
        '[' => {
          self.iter.next();
          Some(Ok(Punctuator(LeftBracket, self.lo)))
        }
        ']' => {
          self.iter.next();
          Some(Ok(Punctuator(RightBracket, self.lo)))
        }
        '{' => {
          self.iter.next();
          Some(Ok(Punctuator(LeftBrace, self.lo)))
        }
        '}' => {
          self.iter.next();
          Some(Ok(Punctuator(RightBrace, self.lo)))
        }
        '|' => {
          self.iter.next();
          Some(Ok(Punctuator(Pipe, self.lo)))
        }
        '.' => {
          if scan_spread(self) {
            Some(Ok(Punctuator(Spread(self.lo), self.hi)))
          } else {
            Some(Err("Unexpected character."))
          }
        }
        '_' | 'a'...'z' | 'A'...'Z' => {
          scan_name(self);
          Some(Ok(Name(&self.input[self.lo..self.hi], self.lo, self.hi)))
        }
        '-' | '0'...'9' => {
          match scan_number(self) {
            (false, false) => Some(Err("Invalid integer number.")),
            (false, true) => Some(Err("Invalid float number.")),
            (true, false) => Some(Ok(IntValue(&self.input[self.lo..self.hi], self.lo, self.hi))),
            (true, true) => Some(Ok(FloatValue(&self.input[self.lo..self.hi], self.lo, self.hi))),
          }
        }
        '"' => {
          match scan_string(self) {
            (false, _) => Some(Err("Unterminated string.")),
            (_, true) => Some(Err("Bad character escape sequence.")),
            _ => Some(Ok(StringValue(&self.input[self.lo..self.hi], self.lo, self.hi))),
          }
        }
        _ => Some(Err("Unexpected character.")),
      }
    }
    item
  }
}

#[cfg(test)]
mod tests {
  use super::Punctuator::*;
  use super::Token::*;
  use super::{Lexer, Token};

  fn test_next_token(lexer: &mut Lexer, expected: Token) {
    let next = lexer.next();
    assert_eq!(Some(Ok(expected)), next);
  }

  fn test_with_lex(input: &str, expeced: Token) {
    let mut lexer = Lexer::new(&input);
    test_next_token(&mut lexer, expeced);
  }

  fn test_str(input: &str, expeced: &str) {
    let len = expeced.len();
    test_with_lex(input, StringValue(expeced, 1, len + 1))
  }

  #[test]
  fn test_string() {
    test_str(r#""simple""#, r#"simple"#);
    test_str(r#"" white space ""#, r#" white space "#);
    test_str(r#""quote \"""#, r#"quote \""#);
    test_str(r#""slashes \\ \/""#, r#"slashes \\ \/"#);
    test_str(r#""unicode \u1234\u5678\u90AB\uCDEF""#,
             r#"unicode \u1234\u5678\u90AB\uCDEF"#);
  }

  #[test]
  fn test_name() {
    let mut lexer = Lexer::new("     name1    name2   \"simple\" \"  white space   \" other_name");
    test_next_token(&mut lexer, Name("name1", 5, 10));
    test_next_token(&mut lexer, Name("name2", 14, 19));
    test_next_token(&mut lexer, StringValue("simple", 23, 29));
    test_next_token(&mut lexer, StringValue("  white space   ", 32, 48));
    test_next_token(&mut lexer, Name("other_name", 50, 60));
    test_next_token(&mut lexer, Eof(50,60));
    assert_eq!(None, lexer.next());
  }

  #[test]
  fn test_number() {
    let mut lexer = Lexer::new("-9 0 9 -0 -9 1234 -1234 0.0 -0.0 1.0 -1.012 -0.101 1.0e2 -1.0E2 \
                                0.00e-002 -0.00E+002 9.1E+0");
    test_next_token(&mut lexer, IntValue("-9", 0, 2));
    test_next_token(&mut lexer, IntValue("0", 3, 4));
    test_next_token(&mut lexer, IntValue("9", 5, 6));
    test_next_token(&mut lexer, IntValue("-0", 7, 9));
    test_next_token(&mut lexer, IntValue("-9", 10, 12));
    test_next_token(&mut lexer, IntValue("1234", 13, 17));
    test_next_token(&mut lexer, IntValue("-1234", 18, 23));
    test_next_token(&mut lexer, FloatValue("0.0", 24, 27));
    test_next_token(&mut lexer, FloatValue("-0.0", 28, 32));
    test_next_token(&mut lexer, FloatValue("1.0", 33, 36));
    test_next_token(&mut lexer, FloatValue("-1.012", 37, 43));
    test_next_token(&mut lexer, FloatValue("-0.101", 44, 50));
    test_next_token(&mut lexer, FloatValue("1.0e2", 51, 56));
    test_next_token(&mut lexer, FloatValue("-1.0E2", 57, 63));
    test_next_token(&mut lexer, FloatValue("0.00e-002", 64, 73));
    test_next_token(&mut lexer, FloatValue("-0.00E+002", 74, 84));
    test_next_token(&mut lexer, FloatValue("9.1E+0", 85, 91));
    test_next_token(&mut lexer, Eof(85,91));
    assert_eq!(None, lexer.next());
  }

  #[test]
  fn test_symbol() {
    let mut lexer = Lexer::new("@ !  :$ =    [  {   (|] } )      ...");
    test_next_token(&mut lexer, Punctuator(At, 0));
    test_next_token(&mut lexer, Punctuator(Bang, 2));
    test_next_token(&mut lexer, Punctuator(Colon, 5));
    test_next_token(&mut lexer, Punctuator(Dollar, 6));
    test_next_token(&mut lexer, Punctuator(Equals, 8));
    test_next_token(&mut lexer, Punctuator(LeftBracket, 13));
    test_next_token(&mut lexer, Punctuator(LeftBrace, 16));
    test_next_token(&mut lexer, Punctuator(LeftParen, 20));
    test_next_token(&mut lexer, Punctuator(Pipe, 21));
    test_next_token(&mut lexer, Punctuator(RightBracket, 22));
    test_next_token(&mut lexer, Punctuator(RightBrace, 24));
    test_next_token(&mut lexer, Punctuator(RightParen, 26));
    test_next_token(&mut lexer, Punctuator(Spread(33), 35));
    test_next_token(&mut lexer, Eof(33,36));
    assert_eq!(None, lexer.next());
  }
}
<|endoftext|>


<commit_before>///! Types and methods for syntax storage and manipulation.

use std;
use std::fmt;
use std::vec::Vec;
use std::default::Default;
use std::ops::{Deref,Range};
use std::hash::{Hash, Hasher};
use std::collections::HashMap;

use super::ordered;
use symbol;
use symbol::Symbol;
use super::util;
use super::util::intrusive;
use super::util::intrusive::{Ref,RefCounted};

pub mod token;
pub use grammar::token::Spec as TokenSpec;
pub use grammar::token::Type as TokenType;
pub use grammar::token::{Token,Nonterminal};

// pub use self::token::Type as TokenType;
// pub use self::token::Spec

/// Per-scope grammar-data index.
pub struct TokenIndex {
    /// Symbol pool used to create new token names.
    pub symbol_pool: Ref<symbol::Pool>,

    /// All tokens directly within this scope.
    pub tokens: HashMap<token::Spec,token::IndexData>,
}

impl TokenIndex {
    /// Fetch the symbol corresponding to a given string.
    pub fn symbol(&self, name: &str) -> Symbol {
        self.symbol_pool.symbol(name)
    }

    /// Find or create a token in this scope.
    ///
    /// @param name Name of the token to find or create.
    pub fn token_by_name(&mut self, name: &str) -> &Token {
        self.token_by_spec(TokenSpec{name: name, ..Default::default()})
    }

    /// Find or create a token in this scope.
    ///
    /// @param spec Attributes the returned token should have.
    pub fn token_by_spec(&mut self, spec: TokenSpec) -> &Token {
        match self.find_token_by_spec(spec) {
            Some(tok) => tok,
            None => self.create_token(spec)
        }
    }

    /// Find a token in the current scope by name.
    pub fn find_token_by_name(&self, name: &str) -> Option<&Token> {
        self.find_token_by_spec(TokenSpec{name: name, ..Default::default()})
    }

    /// Find a token in the current scope by explicitly specifying
    /// its parameters.
    pub fn find_token_by_spec(&self, spec: TokenSpec) -> Option<&Token> {
        let tok = self.tokens.get(spec.name);
        None
    }

    /// Unconditionally create a token.
    fn create_token(&mut self, spec: TokenSpec) -> &Token {
        let nonterminal_name = spec.name.chars().all(|c| c.is_lowercase());
        let terminal_name = spec.name.chars().all(|c| c.is_uppercase());
    }
}
        /* let parts = spec.split(TOKEN_SCOPE_SEPARATOR).collect::<Vec<&str>()>();
         * for part in parts.drain() {
         *
         *         }
         *     }             */
impl intrusive::ExplicitlySized for TokenIndex {
    fn get_type_size(&self) -> usize { std::mem::size_of::<Self>() }
    fn get_type_align(&self) -> usize { std::mem::align_of::<Self>() }
}

impl Eq for TokenIndex {}
impl PartialEq<TokenIndex> for TokenIndex
{
    fn eq(&self, other: &TokenIndex) -> bool {
        self.tokens.iter().all(|(k, v)| other.tokens[*k].deref() == (*v).deref())
    }
}

impl fmt::Debug for TokenIndex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "")
    }
}

/* ****************************************************************
 * Rule
 */

/// A rule within a grammar.  Each rule defines *one* possible representation of
/// a particular Nonterminal in terms of a sequence of tokens, which may include
/// the same Nonterminal.
pub struct Rule
{
    refcount: usize,
    lhs: intrusive::Ref<Nonterminal>,
    rhs: Vec<intrusive::Ref<Token>>
}

impl Rule {
    /// Find all positions on the rule's right-hand side that a particular
    /// token appears.  This is useful for e.g. calculating a token's
    /// follow-set.
    pub fn rhs_indices_of(&self, tok: &Token) -> Vec<usize>
    {
        std::iter::range(0, self.rhs.len()).
            zip(self.rhs.iter()).
            filter_map(|(i, rhs_tok)| if rhs_tok == tok { Some(i) } else { None }).
            collect::<Vec<usize>>()
    }
}

impl token::HasFirstSet for Rule {
    fn first_set_into(&self, out: &mut Vec<Ref<Token>>) {
        for tok in self.rhs.iter() {
            match tok.token_type() {
                TokenType::Terminal => { out.push((*tok).clone()); break; },
                _ => { tok.first_set_into(out);
                       if ! tok.is_nullable() { break; } }
            }
        }
    }
}

impl Hash for Rule {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.lhs.hash(state);
        self.rhs.hash(state);
    }
}

impl fmt::Debug for Rule {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut r = write!(f, "{:?} ::=", (&*self.lhs as &symbol::Nameable).name());
        for x in self.rhs.iter() { r = write!(f, " {:?}", *x) }
        r
    }
}

impl Eq for Rule {}
impl PartialEq<Rule> for Rule {
    fn eq(&self, other: &Rule) -> bool {
        self.lhs == other.lhs && self.rhs == other.rhs
    }
}

impl intrusive::ExplicitlySized for Rule {
    fn get_type_size(&self) -> usize { std::mem::size_of::<Self>() }
    fn get_type_align(&self) -> usize { std::mem::align_of::<Self>() }
}

default_refcounted_impl!(Rule, refcount);

/* ****************************************************************
 * Grammar
 */
/// A set of terminal and nonterminal tokens, and rules that define
/// their relationships.
pub struct Grammar {
    refcount: usize,
    order_manager: ordered::Manager,
    index: TokenIndex,
}

impl Grammar {
    /// Get the top-level token index for the grammar.
    fn get_scope_index(&self) -> &TokenIndex {
        &self.index
    }
}

impl fmt::Debug for Grammar {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "grammar {{\n"));
        for (ref sym, ref tok) in self.index.tokens.iter() {
            for ref rule in self.index.rules_for[**sym].iter() {
                try!(write!(f, "  {:?}\n", rule))
            }
        }
        write!(f, "}}")
    }
}

// impl symbol::scope::HasRootScope<Grammar> for Grammar {
//   fn root_scope(&self) -> intrusive::Ref<Grammar> {
//       intrusive::ref_to(self)
//   }
// }

impl Eq for Grammar {}
impl PartialEq<Grammar> for Grammar {
    fn eq(&self, other: &Grammar) -> bool {
        self.index == other.index
    }
}

impl intrusive::ExplicitlySized for Grammar {
    fn get_type_size(&self) -> usize { std::mem::size_of::<Self>() }
    fn get_type_align(&self) -> usize { std::mem::align_of::<Self>() }
}

default_refcounted_impl!(Grammar, refcount);
<commit_msg>grammar: impl'd TokenIndex; general rewrite.<commit_after>//! Types and methods for syntax storage and manipulation.

use std;
use std::fmt;
use std::vec::Vec;
use std::clone::Clone;
use std::default::Default;
use std::ops::Deref;
use std::hash::{Hash, Hasher};
use std::collections::HashMap;

use ordered;
use symbol;
use symbol::Symbol;
use util::intrusive;
use util::intrusive::{Ref,RefCounted,Reference,RefCountHolder};

pub mod token;
pub use grammar::token::Token;
pub use grammar::token::Spec as TokenSpec;
pub use grammar::token::Type as TokenType;
use grammar::token::{Terminal,Nonterminal,Synthetic,LabeledToken};
use grammar::token::{HasFirstSet,Typed,Nullable,Indexed};

// pub use self::token::Type as TokenType;
// pub use self::token::Spec

/// Per-scope grammar-data index.
pub struct TokenIndex {
    /// Resources this index uses for token IDs and name/label symbols.
    resources: Ref<CommonResources>,

    /// All tokens directly within this scope.
    pub tokens: HashMap<token::Spec,Ref<Token>>,
}

impl TokenIndex {
    fn new(resources: Ref<CommonResources>) -> Self {
        TokenIndex{resources: resources, tokens: HashMap::new()}
    }

    /// Fetch the symbol corresponding to a given string.
    pub fn symbol(&mut self, name: &str) -> Symbol {
        self.resources.symbol_pool.symbol(name)
    }

    /// Find or create a token in this scope.
    ///
    /// @param name Name of the token to find or create.
    pub fn token_by_name(&mut self, name: &str) -> Ref<Token> {
        let sym = self.symbol(name);
        self.token_by_spec(TokenSpec{name: sym, ..Default::default()})
    }

    /// Find or create a token in this scope.
    ///
    /// @param spec Attributes the returned token should have.
    pub fn token_by_spec(&mut self, spec: TokenSpec) -> Ref<Token> {
        match self.find_token_by_spec(spec) {
            Some(tok) => tok,
            None => { let tok = self.create_token(spec).ok().unwrap();
                      self.store_token(spec, tok) }
        }
    }

    /// Find a token in the current scope by name.
    pub fn find_token_by_name(&self, name: Symbol) -> Option<Ref<Token>> {
        self.find_token_by_spec(TokenSpec{name: name, ..Default::default()})
    }

    /// Find a token in the current scope by explicitly specifying
    /// its parameters.
    pub fn find_token_by_spec(&self, spec: TokenSpec) -> Option<Ref<Token>> {
        match self.tokens.get(&spec) {
            Some(ref_tok) => Some(ref_tok.clone()),
            None => None
        }
    }

    fn store_token<'a>(&'a mut self, spec: TokenSpec, tok: Ref<Token>) -> Ref<Token> {
        self.tokens.insert(spec, tok.clone());
        tok
    }

    /// Unconditionally create a token, but don't store it in the index.
    fn create_token(&mut self, spec: TokenSpec) -> Result<Ref<Token>,&str> {
        let name_is_terminal = spec.name.as_slice().chars().all(|c| c.is_uppercase());
        let name_is_nonterminal = spec.name.as_slice().chars().all(|c| c.is_lowercase());
        if ! name_is_terminal && ! name_is_nonterminal { Err("Invalid mixed-case token name") }
        // If this is a synthetic or labeled token, create it as appropriate.
        else if spec.requires_base() {
            let base = self.token_by_spec(spec.base_spec());
            match spec.label {
                Some(lbl) => Ok(Reference::new_on_heap(LabeledToken::new(base, lbl))),
                _ => if spec.repetitions.as_range() == (1..2) { unreachable!() }
                else { Ok(Reference::new_on_heap(Synthetic::new(base, spec.repetitions))) }
            }
            // Otherwise create the basic token.
        } else {
            let order = self.resources.order_manager.next_order(ordered::Category::TOKEN);
            if name_is_terminal {
                Ok(Reference::new_on_heap(Terminal::new(spec.name, order)))
            } else if name_is_nonterminal {
                Ok(Reference::new_on_heap(Nonterminal::new(spec.name, order)))
            } else { unreachable!() }
        }
    }
}

impl Eq for TokenIndex {}
impl PartialEq<TokenIndex> for TokenIndex
{
    fn eq(&self, other: &TokenIndex) -> bool {
        self.tokens.iter().all(|(k, v)| other.tokens[*k].deref() == (*v).deref())
    }
}

impl fmt::Debug for TokenIndex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "")
    }
}

/* ****************************************************************
 * Rule
 */

/// A rule within a grammar.  Each rule defines *one* possible representation of
/// a particular Nonterminal in terms of a sequence of tokens, which may include
/// the same Nonterminal.
pub struct Rule
{
    refcount: usize,
    lhs: intrusive::Ref<Nonterminal>,
    rhs: Vec<intrusive::Ref<Token>>
}

impl Rule {
    /// Find all positions on the rule's right-hand side that a particular
    /// token appears.  This is useful for e.g. calculating a token's
    /// follow-set.
    pub fn rhs_indices_of(&self, tok: &Token) -> Vec<usize>
    {
        std::iter::range(0, self.rhs.len()).
            zip(self.rhs.iter()).
            filter_map(|(i, rhs_tok)| if rhs_tok == tok { Some(i) } else { None }).
            collect::<Vec<usize>>()
    }
}

impl token::HasFirstSet for Rule {
    fn first_set_into(&self, out: &mut Vec<Ref<Token>>) {
        for tok in self.rhs.iter() {
            match tok.token_type() {
                TokenType::Terminal => { out.push((*tok).clone()); break; },
                _ => { tok.first_set_into(out);
                       if ! tok.is_nullable() { break; } }
            }
        }
    }
}

impl Hash for Rule {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.lhs.hash(state);
        for elt in self.rhs.iter() { elt.data_id().hash(state); }
    }
}

impl fmt::Debug for Rule {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut r = write!(f, "{:?} ::=", (&*self.lhs as &symbol::Nameable).name());
        for x in self.rhs.iter() { r = write!(f, " {:?}", *x) }
        r
    }
}

impl Eq for Rule {}
impl PartialEq<Rule> for Rule {
    fn eq(&self, other: &Rule) -> bool {
        self.lhs == other.lhs && self.rhs == other.rhs
    }
}

default_refcounted_impl!(Rule, refcount);

/* ****************************************************************
 * CommonResources
 */
/// Per-grammar resources required by every scope within that grammar.
#[derive(Debug)]
struct CommonResources {
    refcount: usize,
    order_manager: ordered::Manager,
    symbol_pool: symbol::Pool,
}
default_refcounted_impl!(CommonResources);
impl CommonResources {
    fn new() -> CommonResources {
        CommonResources{refcount: 1,
                        symbol_pool: symbol::Pool::new(),
                        order_manager: ordered::Manager::new()}
    }
}

/* ****************************************************************
 * Grammar
 */
/// A set of terminal and nonterminal tokens, and rules that define
/// their relationships.
pub struct Grammar {
    refcount: usize,
    resources: Ref<CommonResources>,
    index: TokenIndex,
}

impl Grammar {
    pub fn new() -> Grammar {
        let resources: Ref<CommonResources> = Reference::new_on_heap(CommonResources::new());
        Grammar{refcount: 1,
                resources: resources.clone(),
                index: TokenIndex::new(resources)}
    }

    /// Get the top-level token index for the grammar.
    pub fn index(&self) -> &TokenIndex {
        &self.index
    }
    pub fn index_mut(&mut self) -> &mut TokenIndex {
        &mut self.index
    }
}

impl fmt::Debug for Grammar {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "grammar {{\n"));
        for (_, ref tok) in self.index.tokens.iter() {
            for ref rule in tok.index_data().rules_for.iter() {
                try!(write!(f, "  {:?}\n", rule))
            }
        }
        write!(f, "}}")
    }
}

// impl symbol::scope::HasRootScope<Grammar> for Grammar {
//   fn root_scope(&self) -> intrusive::Ref<Grammar> {
//       intrusive::ref_to(self)
//   }
// }

impl Eq for Grammar {}
impl PartialEq<Grammar> for Grammar {
    fn eq(&self, other: &Grammar) -> bool {
        self.index == other.index
    }
}

default_refcounted_impl!(Grammar, refcount);
<|endoftext|>