<commit_before>use std::cell::RefCell;
use std::rc::Rc;
use std::sync::mpsc;
use std::thread;
use std::result::Result;

use action::ActionHandlers;
use {config, context, Message, MiliSec, Response, Timer};
use condition::Condition;
use context::event::EventHandler;
use dispatcher::request::{InternalRequest, Request, RequestHandler};
use dispatcher::reactor::RequestReactor;
use dispatcher::demux::Demultiplexer;
use dispatcher::handlers;
use reactor::Reactor;

const TIMER_STEP: MiliSec = 100;

pub struct Correlator {
    action_handlers: ActionHandlers,
    dispatcher_input_channel: mpsc::Sender<Request<Message>>,
    dispatcher_output_channel: mpsc::Receiver<Response>,
    dispatcher_thread_handle: thread::JoinHandle<()>,
    exits_received: u32
}

impl Correlator {
    pub fn new(contexts: Vec<config::Context>, action_handlers: ActionHandlers) -> Correlator {
        let (dispatcher_input_channel, rx) = mpsc::channel();
        let (dispatcher_output_channel_tx, dispatcher_output_channel_rx) = mpsc::channel();
        let _ = Timer::from_chan(TIMER_STEP, dispatcher_input_channel.clone());

        let handle = thread::spawn(move || {
            let dmux = Demultiplexer::new(rx);
            let exit_condition = Condition::new(false);
            let mut reactor = RequestReactor::new(dmux, exit_condition.clone());
            let exit_handler = Box::new(handlers::exit::ExitEventHandler::new(exit_condition));
            reactor.register_handler(exit_handler);

            let mut timer_event_handler = Box::new(handlers::timer::TimerEventHandler::new());
            let mut message_event_handler = Box::new(handlers::message::MessageEventHandler::new());

            let mut event_handlers = Vec::new();
            for i in contexts.into_iter() {
                let context: context::Context = i.into();
                let event_handler: Box<EventHandler<InternalRequest>> = context.into();
                let handler = Rc::new(RefCell::new(event_handler));
                event_handlers.push(handler);
            }

            for i in event_handlers {
                timer_event_handler.register_handler(i.clone());
                message_event_handler.register_handler(i.clone())
            }

            reactor.register_handler(timer_event_handler);
            reactor.register_handler(message_event_handler);
            reactor.handle_events();
        });

        Correlator {
            action_handlers: action_handlers,
            dispatcher_input_channel: dispatcher_input_channel,
            dispatcher_output_channel: dispatcher_output_channel_rx,
            dispatcher_thread_handle: handle,
            exits_received: 0
        }
    }

    pub fn push_message(&mut self, message: Message) -> Result<(), mpsc::SendError<Request<Message>>> {
        self.consume_results();
        self.dispatcher_input_channel.send(Request::Message(message))
    }

    fn consume_results(&mut self) {
        for i in self.dispatcher_output_channel.try_recv() {
            if let Response::Event(result) = i {
                self.action_handlers.handle(result);
            }
        }
    }

    pub fn stop(mut self) -> thread::Result<()> {
        self.consume_results();
        self.stop_dispatcher();
        self.dispatcher_thread_handle.join()
    }

    fn stop_dispatcher(&mut self) {
        let _ = self.dispatcher_input_channel.send(Request::Exit);
        let _ = self.wait_for_dispatcher_to_exit();
    }

    fn wait_for_dispatcher_to_exit(&mut self) -> Result<(), ()> {
        loop {
            let value = self.dispatcher_output_channel.recv();
            match value {
                Ok(value) => {
                    try!(self.handle_command(value))
                },
                _ => {}
            }
        }
    }

    fn handle_command(&mut self, command: Response) -> Result<(), ()> {
        match command {
            Response::Event(result) => self.action_handlers.handle(result),
            Response::Exit => {
                if self.handle_exit_command() {
                    return Err(());
                }
            }
        }
        Ok(())
    }

    fn handle_exit_command(&mut self) -> bool {
        let _ = self.dispatcher_input_channel.send(Request::Exit);
        self.exits_received += 1;
        self.exits_received >= 1
    }
}
<commit_msg>Correlator: rearrange some lines<commit_after>use std::cell::RefCell;
use std::rc::Rc;
use std::sync::mpsc;
use std::thread;
use std::result::Result;

use action::ActionHandlers;
use {config, context, Message, MiliSec, Response, Timer};
use condition::Condition;
use context::event::EventHandler;
use dispatcher::request::{InternalRequest, Request, RequestHandler};
use dispatcher::reactor::RequestReactor;
use dispatcher::demux::Demultiplexer;
use dispatcher::handlers;
use reactor::Reactor;

const TIMER_STEP: MiliSec = 100;

pub struct Correlator {
    action_handlers: ActionHandlers,
    dispatcher_input_channel: mpsc::Sender<Request<Message>>,
    dispatcher_output_channel: mpsc::Receiver<Response>,
    dispatcher_thread_handle: thread::JoinHandle<()>,
    exits_received: u32
}

impl Correlator {
    pub fn new(contexts: Vec<config::Context>, action_handlers: ActionHandlers) -> Correlator {
        let (dispatcher_input_channel, rx) = mpsc::channel();
        let (dispatcher_output_channel_tx, dispatcher_output_channel_rx) = mpsc::channel();
        let _ = Timer::from_chan(TIMER_STEP, dispatcher_input_channel.clone());

        let handle = thread::spawn(move || {
            let dmux = Demultiplexer::new(rx);
            let exit_condition = Condition::new(false);
            let mut reactor = RequestReactor::new(dmux, exit_condition.clone());
            let exit_handler = Box::new(handlers::exit::ExitEventHandler::new(exit_condition));
            let mut timer_event_handler = Box::new(handlers::timer::TimerEventHandler::new());
            let mut message_event_handler = Box::new(handlers::message::MessageEventHandler::new());

            let mut event_handlers = Vec::new();
            for i in contexts.into_iter() {
                let context: context::Context = i.into();
                let event_handler: Box<EventHandler<InternalRequest>> = context.into();
                let handler = Rc::new(RefCell::new(event_handler));
                event_handlers.push(handler);
            }

            for i in event_handlers {
                timer_event_handler.register_handler(i.clone());
                message_event_handler.register_handler(i.clone())
            }

            reactor.register_handler(exit_handler);
            reactor.register_handler(timer_event_handler);
            reactor.register_handler(message_event_handler);
            reactor.handle_events();
        });

        Correlator {
            action_handlers: action_handlers,
            dispatcher_input_channel: dispatcher_input_channel,
            dispatcher_output_channel: dispatcher_output_channel_rx,
            dispatcher_thread_handle: handle,
            exits_received: 0
        }
    }

    pub fn push_message(&mut self, message: Message) -> Result<(), mpsc::SendError<Request<Message>>> {
        self.consume_results();
        self.dispatcher_input_channel.send(Request::Message(message))
    }

    fn consume_results(&mut self) {
        for i in self.dispatcher_output_channel.try_recv() {
            if let Response::Event(result) = i {
                self.action_handlers.handle(result);
            }
        }
    }

    pub fn stop(mut self) -> thread::Result<()> {
        self.consume_results();
        self.stop_dispatcher();
        self.dispatcher_thread_handle.join()
    }

    fn stop_dispatcher(&mut self) {
        let _ = self.dispatcher_input_channel.send(Request::Exit);
        let _ = self.wait_for_dispatcher_to_exit();
    }

    fn wait_for_dispatcher_to_exit(&mut self) -> Result<(), ()> {
        loop {
            let value = self.dispatcher_output_channel.recv();
            match value {
                Ok(value) => {
                    try!(self.handle_command(value))
                },
                _ => {}
            }
        }
    }

    fn handle_command(&mut self, command: Response) -> Result<(), ()> {
        match command {
            Response::Event(result) => self.action_handlers.handle(result),
            Response::Exit => {
                if self.handle_exit_command() {
                    return Err(());
                }
            }
        }
        Ok(())
    }

    fn handle_exit_command(&mut self) -> bool {
        let _ = self.dispatcher_input_channel.send(Request::Exit);
        self.exits_received += 1;
        self.exits_received >= 1
    }
}
<|endoftext|>


<commit_before>#![crate_type = "bin"]
#![feature(slice_patterns)]

extern crate protobuf;

use std::fs::*;
use std::io::Read;
use std::io::Write;
use std::path::Path;

use protobuf::parse_from_reader;
use protobuf::descriptor::*;
use protobuf::codegen::*;

fn write_file(bin: &str) {
    let mut is = File::open(&Path::new(bin)).unwrap();
    let fds = parse_from_reader::<FileDescriptorSet>(&mut is as &mut Read).unwrap();

    let file_names: Vec<String> = fds.get_file().iter()
        .map(|f| f.get_name().to_string())
        .collect();
    let results = gen(fds.get_file(), &file_names);

    for r in results.iter() {
        let mut file_writer = File::create(&Path::new(&r.name)).unwrap();
        file_writer.write(&r.content).unwrap();
    }
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    if args.len() != 2 {
        panic!("must have exactly one argument");
    }
    let ref pb_bin = args[1];
    write_file(&pb_bin);
}
<commit_msg>fix build against beta<commit_after>#![crate_type = "bin"]

extern crate protobuf;

use std::fs::*;
use std::io::Read;
use std::io::Write;
use std::path::Path;

use protobuf::parse_from_reader;
use protobuf::descriptor::*;
use protobuf::codegen::*;

fn write_file(bin: &str) {
    let mut is = File::open(&Path::new(bin)).unwrap();
    let fds = parse_from_reader::<FileDescriptorSet>(&mut is as &mut Read).unwrap();

    let file_names: Vec<String> = fds.get_file().iter()
        .map(|f| f.get_name().to_string())
        .collect();
    let results = gen(fds.get_file(), &file_names);

    for r in results.iter() {
        let mut file_writer = File::create(&Path::new(&r.name)).unwrap();
        file_writer.write(&r.content).unwrap();
    }
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    if args.len() != 2 {
        panic!("must have exactly one argument");
    }
    let ref pb_bin = args[1];
    write_file(&pb_bin);
}
<|endoftext|>


<commit_before>extern crate byteorder;
extern crate crc;

use std::result::*;
use std::io;
use std::io::{BufReader, ErrorKind, Read, Seek, SeekFrom, Error};
use self::byteorder::{ByteOrder, ReadBytesExt, LittleEndian};
use self::crc::{crc32, Hasher32};

use definitions::*;
use compress::{max_compressed_len};

// The Max Encoded Length of the Max Chunk of 65536 bytes
const MAX_BUFFER_SIZE: usize = 76_490;

pub struct Decompressor<R: Read> {
	inner: BufReader<R>,
	decoded: [u8; MAX_UNCOMPRESSED_CHUNK_LEN as usize],
	buf: [u8; MAX_BUFFER_SIZE + (CHECK_SUM_SIZE as usize)],
	// decoded[i:j] contains decoded bytes that have not yet been passed on.
	i: usize,
	j: usize,
	read_header: bool,
}

impl <R: Read> Decompressor<R> {

	pub fn new(inner: R) -> Decompressor<R> {
		Decompressor {
			inner: BufReader::new(inner),
			decoded: [0; MAX_UNCOMPRESSED_CHUNK_LEN as usize],
			buf: [0; MAX_BUFFER_SIZE + (CHECK_SUM_SIZE as usize)],
			i: 0,
			j: 0,
			read_header: false,
		}
	}
}

impl <R: Read> Read for Decompressor<R> {
	// Implement Read
	// Source (Inner) Buffer into Destination Buffer, returning how many bytes were read.
	fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
		loop {

			if self.i < self.j {
				let mut s = 0;
				for (d, l) in dst.iter_mut().zip(self.decoded.split_at(self.i).1.split_at(self.j).0.iter()) {
			        *d = *l;
			        s += 1;
			    }
			    self.i += s;
			    return Ok(s)
			}

			// Grab Chunk Header
			if self.inner.read(self.buf.split_at_mut(4).0).unwrap() != 4 {
				return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"))
			}

			// Read Chunk Type
			let chunk_type = self.buf[0];
			if !self.read_header {
				if chunk_type != CHUNK_TYPE_STREAM_IDENTIFIER {
					return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"))
				}
				self.read_header = true;
			}

			// Read Chunk Length
			let chunk_len = self.buf[1] as usize | ((self.buf[2] as usize) << 8) | ((self.buf[3] as usize) << 16);
			if chunk_len > self.buf.len() {
				return Err(Error::new(ErrorKind::InvalidInput, "snappy: unsupported input"))
			}

			// The chunk types are specified at
			// https://github.com/google/snappy/blob/master/framing_format.txt
			match chunk_type {

				// Section 4.2. Compressed data (chunk type 0x00).
				CHUNK_TYPE_COMPRESSED_DATA => {
					if chunk_len < (CHECK_SUM_SIZE as usize) {
						return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"))
					}
					// Setup Buffer Slice with Chunk Length
					let buf: &mut [u8] = self.buf.split_at_mut(chunk_len as usize).0;

					// Read into Buffer
					if self.inner.read(buf).unwrap() != chunk_len {
						return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"))
					}

					// Read Checksum
					let check_sum = buf[0] as u32 | ((buf[1] as u32) << 8) | ((buf[2] as u32) << 16) | ((buf[3] as u32) << 24);

					// TODO:
					// Figure Out Borrowing and Modifying Buffer Slice instead of Copying.
					// buf = buf.split_at_mut(CHECK_SUM_SIZE as usize).1;
					let mut buf1 = buf.split_at_mut(CHECK_SUM_SIZE as usize).1;

					// Check Decompressed Length
					let n = decompressed_len(buf1.as_ref());
					if n as usize > self.decoded.len() {
						return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"))
					}

					// Decompress
					try!(decompress(self.decoded.as_mut(), buf1));

					// Check Checksum
					if crc32::checksum_ieee(self.decoded.split_at(n as usize).0) != check_sum {
						return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"))
					}

					self.i = 0;
					self.j = n as usize;
					continue;
				},
				// Section 4.3. Uncompressed data (chunk type 0x01).
				CHUNK_TYPE_UNCOMPRESSED_DATA => {},
				// Section 4.1. Stream identifier (chunk type 0xff).
				CHUNK_TYPE_STREAM_IDENTIFIER => {},

				// Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f).
				_ => {
					return Err(Error::new(ErrorKind::InvalidInput, "snappy: unsupported input"))
				}

			}

			unimplemented!()

		}
	}
}

// decompressed_len returns the length of the decoded block.
pub fn decompressed_len(src: &[u8]) -> u64 {
	LittleEndian::read_u64(src)
}

// Decompress reads the decoded form of src into dst and returns the length
// read.
// Returns an error if dst was not large enough to hold the entire decoded
// block.
fn decompress(dst: &mut [u8], src: &mut [u8]) -> io::Result<usize> {
	// TODO: Handle Error
	let dLen = decompressed_len(src) as usize;
	// TODO FIX!!
	// For now, always assume 8 bytes used for src header length
	let mut s: usize = 8;

	if dst.len() < dLen {
        return Err(Error::new(ErrorKind::InvalidInput, "snappy: destination buffer is too short"));
    }

    let (mut d, mut offset, mut length): (usize, usize, usize) = (0,0,0);

    while s < src.len() {
    	match src[s] & 0x03 {

			// Parse a Literal Chunk
    		TAG_LITERAL => {

    			let mut x = (src[s] >> 2) as usize;
    			match x {
	    			0...59 => s += 1,
    				60 => {
    					s += 2;
    					if s > src.len() {
					        return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"));
    					};
    					x = src[s-1] as usize;
    				},
    				61 => {
    					s += 3;
    					if s > src.len() {
					        return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"));
    					};
    					x = (src[s-2] as usize) | ((src[s-1] as usize) << 8);
    				},
    				62 => {
    					s += 4;
    					if s > src.len() {
					        return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"));
    					};
    					x = (src[s-3] as usize) | ((src[s-2] as usize) << 8) | ((src[s-1] as usize) << 16);
    				},
    				63 => {
    					s += 5;
    					if s > src.len() {
					        return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"));
    					};
    					x = (src[s-4] as usize) | ((src[s-3] as usize) << 8) | ((src[s-2] as usize) << 16) | ((src[s-1] as usize) << 24);
    				},
    				_ => {}
    			}
    			length = x.wrapping_add(1);

    			if length as isize <= 0 {
			        return Err(Error::new(ErrorKind::InvalidInput, "snappy: unsupported literal length"));
    			}
    			if length > dst.len() - d || length > src.len() - s {
			        return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"));
    			}

    			// Copy src[s: s+length] to dst[d:0]
    			for (id, is) in dst.split_at_mut(d).1.iter_mut().zip(src.split_at(s).1.split_at(s+length).0.iter()) {
			        *id = *is;
			    }
			    d += length;
			    s += length;
			    continue;
    		},

    		// Parse a Copy1 Chunk
    		TAG_COPY_1 => {
    			s+= 2;
    			if s > src.len() {
			        return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"));
				};
				length = 4 + (src[s-2] as usize)>>2&0x7;
				offset = ((src[s-2] as usize)&0xe0<<3) | (src[s-1] as usize);
    		},

    		// Parse a Copy2 Chunk
    		TAG_COPY_2 => {
    			s+= 3;
    			if s > src.len() {
			        return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"));
				};
				length = 1 + (src[s-3] as usize)>>2;
				offset = (src[s-2] as usize) | ((src[s-1] as usize)<<8);
    		},

    		// Parse a Copy4
    		TAG_COPY_4 => {
		        return Err(Error::new(ErrorKind::InvalidInput, "snappy: unsupported COPY_4 tag"));
    		},

    		_ => unreachable!()
    	};

    	let end = d + length;
    	if offset > d || end > dst.len() {
	        return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"));
	    }
    	while d < end {
    		d += 1;
    		dst[d] = dst[d-offset];
    	}
    }
    if d != dLen {
        return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"));
    }
    Ok(d)
}

<commit_msg>Port Uncompressed Data Tag Parsing (Also icky)<commit_after>extern crate byteorder;
extern crate crc;

use std::result::*;
use std::io;
use std::io::{BufReader, ErrorKind, Read, Seek, SeekFrom, Error};
use self::byteorder::{ByteOrder, ReadBytesExt, LittleEndian};
use self::crc::{crc32, Hasher32};

use definitions::*;
use compress::{max_compressed_len};

// The Max Encoded Length of the Max Chunk of 65536 bytes
const MAX_BUFFER_SIZE: usize = 76_490;

pub struct Decompressor<R: Read> {
	inner: BufReader<R>,
	decoded: [u8; MAX_UNCOMPRESSED_CHUNK_LEN as usize],
	buf: [u8; MAX_BUFFER_SIZE + (CHECK_SUM_SIZE as usize)],
	// decoded[i:j] contains decoded bytes that have not yet been passed on.
	i: usize,
	j: usize,
	read_header: bool,
}

impl <R: Read> Decompressor<R> {

	pub fn new(inner: R) -> Decompressor<R> {
		Decompressor {
			inner: BufReader::new(inner),
			decoded: [0; MAX_UNCOMPRESSED_CHUNK_LEN as usize],
			buf: [0; MAX_BUFFER_SIZE + (CHECK_SUM_SIZE as usize)],
			i: 0,
			j: 0,
			read_header: false,
		}
	}
}

impl <R: Read> Read for Decompressor<R> {
	// Implement Read
	// Source (Inner) Buffer into Destination Buffer, returning how many bytes were read.
	fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
		loop {

			if self.i < self.j {
				let mut s = 0;
				for (d, l) in dst.iter_mut().zip(self.decoded.split_at(self.i).1.split_at(self.j).0.iter()) {
			        *d = *l;
			        s += 1;
			    }
			    self.i += s;
			    return Ok(s)
			}

			// Grab Chunk Header
			if self.inner.read(self.buf.split_at_mut(4).0).unwrap() != 4 {
				return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"))
			}

			// Read Chunk Type
			let chunk_type = self.buf[0];
			if !self.read_header {
				if chunk_type != CHUNK_TYPE_STREAM_IDENTIFIER {
					return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"))
				}
				self.read_header = true;
			}

			// Read Chunk Length
			let chunk_len = self.buf[1] as usize | ((self.buf[2] as usize) << 8) | ((self.buf[3] as usize) << 16);
			if chunk_len > self.buf.len() {
				return Err(Error::new(ErrorKind::InvalidInput, "snappy: unsupported input"))
			}

			// The chunk types are specified at
			// https://github.com/google/snappy/blob/master/framing_format.txt
			match chunk_type {

				// Section 4.2. Compressed data (chunk type 0x00).
				CHUNK_TYPE_COMPRESSED_DATA => {
					if chunk_len < (CHECK_SUM_SIZE as usize) {
						return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"))
					}
					// Setup Buffer Slice with Chunk Length
					let buf: &mut [u8] = self.buf.split_at_mut(chunk_len as usize).0;

					// Read into Buffer
					if self.inner.read(buf).unwrap() != chunk_len {
						return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"))
					}

					// Read Checksum
					let check_sum = buf[0] as u32 | ((buf[1] as u32) << 8) | ((buf[2] as u32) << 16) | ((buf[3] as u32) << 24);

					// TODO:
					// Figure Out Borrowing and Modifying Buffer Slice instead of Copying.
					// buf = buf.split_at_mut(CHECK_SUM_SIZE as usize).1;
					let mut buf1 = buf.split_at_mut(CHECK_SUM_SIZE as usize).1;

					// Check Decompressed Length
					let n = decompressed_len(buf1.as_ref()) as usize;
					if n > self.decoded.len() {
						return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"))
					}

					// Decompress
					try!(decompress(self.decoded.as_mut(), buf1));

					// Check Checksum
					if crc32::checksum_ieee(self.decoded.split_at(n).0) != check_sum {
						return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"))
					}

					self.i = 0;
					self.j = n;
					continue;
				},
				// Section 4.3. Uncompressed data (chunk type 0x01).
				CHUNK_TYPE_UNCOMPRESSED_DATA => {
					if chunk_len < (CHECK_SUM_SIZE as usize) {
						return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"))
					}

					// Read Checksum using self.buf slice
					let check_buf: &mut [u8] = self.buf.split_at_mut(CHECK_SUM_SIZE as usize).0;

					// Read into Checksum Buffer
					if self.inner.read(check_buf).unwrap() != chunk_len {
						return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"))
					}
					// Read Checksum
					let check_sum = check_buf[0] as u32 | ((check_buf[1] as u32) << 8) | ((check_buf[2] as u32) << 16) | ((check_buf[3] as u32) << 24);

					// Read Directly into self.decoded instead of self.buf
					let n = chunk_len - (CHECK_SUM_SIZE as usize);
					// Read into self.decoded Buffer
					if self.inner.read(self.decoded.split_at_mut(n).0).unwrap() != chunk_len {
						return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"))
					}

					// Check Checksum
					if crc32::checksum_ieee(self.decoded.split_at(n).0) != check_sum {
						return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"))
					}

					self.i = 0;
					self.j = n;
					continue;
				},
				// Section 4.1. Stream identifier (chunk type 0xff).
				CHUNK_TYPE_STREAM_IDENTIFIER => {},

				// Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f).
				_ => {
					return Err(Error::new(ErrorKind::InvalidInput, "snappy: unsupported input"))
				}

			}

			unimplemented!()

		}
	}
}

// decompressed_len returns the length of the decoded block.
pub fn decompressed_len(src: &[u8]) -> u64 {
	LittleEndian::read_u64(src)
}

// Decompress reads the decoded form of src into dst and returns the length
// read.
// Returns an error if dst was not large enough to hold the entire decoded
// block.
fn decompress(dst: &mut [u8], src: &mut [u8]) -> io::Result<usize> {
	// TODO: Handle Error
	let dLen = decompressed_len(src) as usize;
	// TODO FIX!!
	// For now, always assume 8 bytes used for src header length
	let mut s: usize = 8;

	if dst.len() < dLen {
        return Err(Error::new(ErrorKind::InvalidInput, "snappy: destination buffer is too short"));
    }

    let (mut d, mut offset, mut length): (usize, usize, usize) = (0,0,0);

    while s < src.len() {
    	match src[s] & 0x03 {

			// Parse a Literal Chunk
    		TAG_LITERAL => {

    			let mut x = (src[s] >> 2) as usize;
    			match x {
	    			0...59 => s += 1,
    				60 => {
    					s += 2;
    					if s > src.len() {
					        return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"));
    					};
    					x = src[s-1] as usize;
    				},
    				61 => {
    					s += 3;
    					if s > src.len() {
					        return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"));
    					};
    					x = (src[s-2] as usize) | ((src[s-1] as usize) << 8);
    				},
    				62 => {
    					s += 4;
    					if s > src.len() {
					        return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"));
    					};
    					x = (src[s-3] as usize) | ((src[s-2] as usize) << 8) | ((src[s-1] as usize) << 16);
    				},
    				63 => {
    					s += 5;
    					if s > src.len() {
					        return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"));
    					};
    					x = (src[s-4] as usize) | ((src[s-3] as usize) << 8) | ((src[s-2] as usize) << 16) | ((src[s-1] as usize) << 24);
    				},
    				_ => {}
    			}
    			length = x.wrapping_add(1);

    			if length as isize <= 0 {
			        return Err(Error::new(ErrorKind::InvalidInput, "snappy: unsupported literal length"));
    			}
    			if length > dst.len() - d || length > src.len() - s {
			        return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"));
    			}

    			// Copy src[s: s+length] to dst[d:0]
    			for (id, is) in dst.split_at_mut(d).1.iter_mut().zip(src.split_at(s).1.split_at(s+length).0.iter()) {
			        *id = *is;
			    }
			    d += length;
			    s += length;
			    continue;
    		},

    		// Parse a Copy1 Chunk
    		TAG_COPY_1 => {
    			s+= 2;
    			if s > src.len() {
			        return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"));
				};
				length = 4 + (src[s-2] as usize)>>2&0x7;
				offset = ((src[s-2] as usize)&0xe0<<3) | (src[s-1] as usize);
    		},

    		// Parse a Copy2 Chunk
    		TAG_COPY_2 => {
    			s+= 3;
    			if s > src.len() {
			        return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"));
				};
				length = 1 + (src[s-3] as usize)>>2;
				offset = (src[s-2] as usize) | ((src[s-1] as usize)<<8);
    		},

    		// Parse a Copy4
    		TAG_COPY_4 => {
		        return Err(Error::new(ErrorKind::InvalidInput, "snappy: unsupported COPY_4 tag"));
    		},

    		_ => unreachable!()
    	};

    	let end = d + length;
    	if offset > d || end > dst.len() {
	        return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"));
	    }
    	while d < end {
    		d += 1;
    		dst[d] = dst[d-offset];
    	}
    }
    if d != dLen {
        return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"));
    }
    Ok(d)
}

<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};

/// A dependency handled by Cargo
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Dependency {
    /// The name of the dependency (as it is set in its `Cargo.toml` and known to crates.io)
    pub name: String,
    optional: bool,
    /// List of features to add (or None to keep features unchanged).
    pub features: Option<Vec<String>>,
    default_features: bool,
    source: DependencySource,
    /// If the dependency is renamed, this is the new name for the dependency
    /// as a string.  None if it is not renamed.
    rename: Option<String>,

    /// Features that are exposed by the dependency
    pub available_features: Vec<String>,
}

impl Dependency {
    /// Create a new dependency with a name
    pub fn new(name: &str) -> Dependency {
        Dependency {
            name: name.into(),
            ..Dependency::default()
        }
    }

    /// Set dependency to a given version
    pub fn set_version(mut self, version: &str) -> Dependency {
        // versions might have semver metadata appended which we do not want to
        // store in the cargo toml files.  This would cause a warning upon compilation
        // ("version requirement […] includes semver metadata which will be ignored")
        let version = version.split('+').next().unwrap();
        let (old_path, old_registry) = match self.source {
            DependencySource::Version { path, registry, .. } => (path, registry),
            _ => (None, None),
        };
        self.source = DependencySource::Version {
            version: Some(version.into()),
            path: old_path,
            registry: old_registry,
        };
        self
    }

    /// Set the available features of the dependency to a given vec
    pub fn set_available_features(mut self, available_features: Vec<String>) -> Dependency {
        self.available_features = available_features;
        self
    }

    /// Set dependency to a given repository
    pub fn set_git(
        mut self,
        repo: &str,
        branch: Option<String>,
        tag: Option<String>,
        rev: Option<String>,
    ) -> Dependency {
        self.source = DependencySource::Git {
            repo: repo.into(),
            branch,
            tag,
            rev,
        };
        self
    }

    /// Set dependency to a given path
    ///
    /// # Panic
    ///
    /// Panics if the path is relative
    pub fn set_path(mut self, path: PathBuf) -> Dependency {
        assert!(
            path.is_absolute(),
            "Absolute path needed, got: {}",
            path.display()
        );
        let old_version = match self.source {
            DependencySource::Version { version, .. } => version,
            _ => None,
        };
        self.source = DependencySource::Version {
            version: old_version,
            path: Some(path),
            registry: None,
        };
        self
    }

    /// Set whether the dependency is optional
    pub fn set_optional(mut self, opt: bool) -> Dependency {
        self.optional = opt;
        self
    }
    /// Set features as an array of string (does some basic parsing)
    pub fn set_features(mut self, features: Option<Vec<String>>) -> Dependency {
        self.features = features;
        self
    }

    /// Set the value of default-features for the dependency
    pub fn set_default_features(mut self, default_features: bool) -> Dependency {
        self.default_features = default_features;
        self
    }

    /// Set the alias for the dependency
    pub fn set_rename(mut self, rename: &str) -> Dependency {
        self.rename = Some(rename.into());
        self
    }

    /// Get the dependency name as defined in the manifest,
    /// that is, either the alias (rename field if Some),
    /// or the official package name (name field).
    pub fn name_in_manifest(&self) -> &str {
        self.rename().unwrap_or(&self.name)
    }

    /// Set the value of registry for the dependency
    pub fn set_registry(mut self, registry: &str) -> Dependency {
        let old_version = match self.source {
            DependencySource::Version { version, .. } => version,
            _ => None,
        };
        self.source = DependencySource::Version {
            version: old_version,
            path: None,
            registry: Some(registry.into()),
        };
        self
    }

    /// Get version of dependency
    pub fn version(&self) -> Option<&str> {
        if let DependencySource::Version {
            version: Some(ref version),
            ..
        } = self.source
        {
            Some(version)
        } else {
            None
        }
    }

    /// Get the path of the dependency
    pub fn path(&self) -> Option<&Path> {
        if let DependencySource::Version {
            path: Some(ref path),
            ..
        } = self.source
        {
            Some(path.as_path())
        } else {
            None
        }
    }

    /// Get the alias for the dependency (if any)
    pub fn rename(&self) -> Option<&str> {
        self.rename.as_deref()
    }

    /// Convert dependency to TOML
    ///
    /// Returns a tuple with the dependency's name and either the version as a `String`
    /// or the path/git repository as an `InlineTable`.
    /// (If the dependency is set as `optional` or `default-features` is set to `false`,
    /// an `InlineTable` is returned in any case.)
    ///
    /// # Panic
    ///
    /// Panics if the path is relative
    pub fn to_toml(&self, crate_root: &Path) -> (String, toml_edit::Item) {
        assert!(
            crate_root.is_absolute(),
            "Absolute path needed, got: {}",
            crate_root.display()
        );
        let data: toml_edit::Item = match (
            self.optional,
            self.features.as_ref(),
            self.default_features,
            self.source.clone(),
            self.rename.as_ref(),
        ) {
            // Extra short when version flag only
            (
                false,
                None,
                true,
                DependencySource::Version {
                    version: Some(v),
                    path: None,
                    registry: None,
                },
                None,
            ) => toml_edit::value(v),
            // Other cases are represented as an inline table
            (optional, features, default_features, source, rename) => {
                let mut data = toml_edit::InlineTable::default();

                match source {
                    DependencySource::Version {
                        version,
                        path,
                        registry,
                    } => {
                        if let Some(v) = version {
                            data.get_or_insert("version", v);
                        }
                        if let Some(p) = path {
                            let relpath = pathdiff::diff_paths(p, crate_root)
                                .expect("both paths are absolute");
                            let relpath = relpath.to_str().unwrap().replace('\\', "/");
                            data.get_or_insert("path", relpath);
                        }
                        if let Some(r) = registry {
                            data.get_or_insert("registry", r);
                        }
                    }
                    DependencySource::Git {
                        repo,
                        branch,
                        tag,
                        rev,
                    } => {
                        data.get_or_insert("git", repo);
                        if let Some(branch) = branch {
                            data.get_or_insert("branch", branch);
                        }
                        if let Some(tag) = tag {
                            data.get_or_insert("tag", tag);
                        }
                        if let Some(rev) = rev {
                            data.get_or_insert("rev", rev);
                        }
                    }
                }
                if self.optional {
                    data.get_or_insert("optional", optional);
                }
                if let Some(features) = features {
                    let features: toml_edit::Value = features.iter().cloned().collect();
                    data.get_or_insert("features", features);
                }
                if !self.default_features {
                    data.get_or_insert("default-features", default_features);
                }
                if rename.is_some() {
                    data.get_or_insert("package", self.name.clone());
                }

                data.fmt();
                toml_edit::value(toml_edit::Value::InlineTable(data))
            }
        };

        (self.name_in_manifest().to_string(), data)
    }
}

impl Default for Dependency {
    fn default() -> Dependency {
        Dependency {
            name: "".into(),
            rename: None,
            optional: false,
            features: None,
            default_features: true,
            source: DependencySource::Version {
                version: None,
                path: None,
                registry: None,
            },
            available_features: vec![],
        }
    }
}

#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone)]
enum DependencySource {
    Version {
        version: Option<String>,
        path: Option<PathBuf>,
        registry: Option<String>,
    },
    Git {
        repo: String,
        branch: Option<String>,
        tag: Option<String>,
        rev: Option<String>,
    },
}

#[cfg(test)]
mod tests {
    use crate::dependency::Dependency;
    use std::path::Path;

    #[test]
    fn to_toml_simple_dep() {
        let crate_root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let toml = Dependency::new("dep").to_toml(&crate_root);

        assert_eq!(toml.0, "dep".to_owned());
    }

    #[test]
    fn to_toml_simple_dep_with_version() {
        let crate_root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let toml = Dependency::new("dep")
            .set_version("1.0")
            .to_toml(&crate_root);

        assert_eq!(toml.0, "dep".to_owned());
        assert_eq!(toml.1.as_str(), Some("1.0"));
    }

    #[test]
    fn to_toml_optional_dep() {
        let crate_root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let toml = Dependency::new("dep")
            .set_optional(true)
            .to_toml(&crate_root);

        assert_eq!(toml.0, "dep".to_owned());
        assert!(toml.1.is_inline_table());

        let dep = toml.1.as_inline_table().unwrap();
        assert_eq!(dep.get("optional").unwrap().as_bool(), Some(true));
    }

    #[test]
    fn to_toml_dep_without_default_features() {
        let crate_root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let toml = Dependency::new("dep")
            .set_default_features(false)
            .to_toml(&crate_root);

        assert_eq!(toml.0, "dep".to_owned());
        assert!(toml.1.is_inline_table());

        let dep = toml.1.as_inline_table().unwrap();
        assert_eq!(dep.get("default-features").unwrap().as_bool(), Some(false));
    }

    #[test]
    fn to_toml_dep_with_path_source() {
        let root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let crate_root = root.join("foo");
        let toml = Dependency::new("dep")
            .set_path(root.join("bar"))
            .to_toml(&crate_root);

        assert_eq!(toml.0, "dep".to_owned());
        assert!(toml.1.is_inline_table());

        let dep = toml.1.as_inline_table().unwrap();
        assert_eq!(dep.get("path").unwrap().as_str(), Some("../bar"));
    }

    #[test]
    fn to_toml_dep_with_git_source() {
        let crate_root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let toml = Dependency::new("dep")
            .set_git("https://foor/bar.git", None, None, None)
            .to_toml(&crate_root);

        assert_eq!(toml.0, "dep".to_owned());
        assert!(toml.1.is_inline_table());

        let dep = toml.1.as_inline_table().unwrap();
        assert_eq!(
            dep.get("git").unwrap().as_str(),
            Some("https://foor/bar.git")
        );
    }

    #[test]
    fn to_toml_renamed_dep() {
        let crate_root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let toml = Dependency::new("dep").set_rename("d").to_toml(&crate_root);

        assert_eq!(toml.0, "d".to_owned());
        assert!(toml.1.is_inline_table());

        let dep = toml.1.as_inline_table().unwrap();
        assert_eq!(dep.get("package").unwrap().as_str(), Some("dep"));
    }

    #[test]
    fn to_toml_dep_from_alt_registry() {
        let crate_root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let toml = Dependency::new("dep")
            .set_registry("alternative")
            .to_toml(&crate_root);

        assert_eq!(toml.0, "dep".to_owned());
        assert!(toml.1.is_inline_table());

        let dep = toml.1.as_inline_table().unwrap();
        assert_eq!(dep.get("registry").unwrap().as_str(), Some("alternative"));
    }

    #[test]
    fn to_toml_complex_dep() {
        let crate_root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let toml = Dependency::new("dep")
            .set_version("1.0")
            .set_default_features(false)
            .set_rename("d")
            .to_toml(&crate_root);

        assert_eq!(toml.0, "d".to_owned());
        assert!(toml.1.is_inline_table());

        let dep = toml.1.as_inline_table().unwrap();
        assert_eq!(dep.get("package").unwrap().as_str(), Some("dep"));
        assert_eq!(dep.get("version").unwrap().as_str(), Some("1.0"));
        assert_eq!(dep.get("default-features").unwrap().as_bool(), Some(false));
    }

    #[test]
    fn paths_with_forward_slashes_are_left_as_is() {
        let crate_root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let path = crate_root.join("sibling/crate");
        let relpath = "sibling/crate";
        let dep = Dependency::new("dep").set_path(path);

        let (_, toml) = dep.to_toml(&crate_root);

        let table = toml.as_inline_table().unwrap();
        let got = table.get("path").unwrap().as_str().unwrap();
        assert_eq!(got, relpath);
    }

    #[test]
    #[cfg(windows)]
    fn normalise_windows_style_paths() {
        let crate_root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let original = crate_root.join(r"sibling\crate");
        let should_be = "sibling/crate";
        let dep = Dependency::new("dep").set_path(original);

        let (_, toml) = dep.to_toml(&crate_root);

        let table = toml.as_inline_table().unwrap();
        let got = table.get("path").unwrap().as_str().unwrap();
        assert_eq!(got, should_be);
    }
}
<commit_msg>refactor: Clean up tests<commit_after>use std::path::{Path, PathBuf};

/// A dependency handled by Cargo
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Dependency {
    /// The name of the dependency (as it is set in its `Cargo.toml` and known to crates.io)
    pub name: String,
    optional: bool,
    /// List of features to add (or None to keep features unchanged).
    pub features: Option<Vec<String>>,
    default_features: bool,
    source: DependencySource,
    /// If the dependency is renamed, this is the new name for the dependency
    /// as a string.  None if it is not renamed.
    rename: Option<String>,

    /// Features that are exposed by the dependency
    pub available_features: Vec<String>,
}

impl Dependency {
    /// Create a new dependency with a name
    pub fn new(name: &str) -> Dependency {
        Dependency {
            name: name.into(),
            ..Dependency::default()
        }
    }

    /// Set dependency to a given version
    pub fn set_version(mut self, version: &str) -> Dependency {
        // versions might have semver metadata appended which we do not want to
        // store in the cargo toml files.  This would cause a warning upon compilation
        // ("version requirement […] includes semver metadata which will be ignored")
        let version = version.split('+').next().unwrap();
        let (old_path, old_registry) = match self.source {
            DependencySource::Version { path, registry, .. } => (path, registry),
            _ => (None, None),
        };
        self.source = DependencySource::Version {
            version: Some(version.into()),
            path: old_path,
            registry: old_registry,
        };
        self
    }

    /// Set the available features of the dependency to a given vec
    pub fn set_available_features(mut self, available_features: Vec<String>) -> Dependency {
        self.available_features = available_features;
        self
    }

    /// Set dependency to a given repository
    pub fn set_git(
        mut self,
        repo: &str,
        branch: Option<String>,
        tag: Option<String>,
        rev: Option<String>,
    ) -> Dependency {
        self.source = DependencySource::Git {
            repo: repo.into(),
            branch,
            tag,
            rev,
        };
        self
    }

    /// Set dependency to a given path
    ///
    /// # Panic
    ///
    /// Panics if the path is relative
    pub fn set_path(mut self, path: PathBuf) -> Dependency {
        assert!(
            path.is_absolute(),
            "Absolute path needed, got: {}",
            path.display()
        );
        let old_version = match self.source {
            DependencySource::Version { version, .. } => version,
            _ => None,
        };
        self.source = DependencySource::Version {
            version: old_version,
            path: Some(path),
            registry: None,
        };
        self
    }

    /// Set whether the dependency is optional
    pub fn set_optional(mut self, opt: bool) -> Dependency {
        self.optional = opt;
        self
    }
    /// Set features as an array of string (does some basic parsing)
    pub fn set_features(mut self, features: Option<Vec<String>>) -> Dependency {
        self.features = features;
        self
    }

    /// Set the value of default-features for the dependency
    pub fn set_default_features(mut self, default_features: bool) -> Dependency {
        self.default_features = default_features;
        self
    }

    /// Set the alias for the dependency
    pub fn set_rename(mut self, rename: &str) -> Dependency {
        self.rename = Some(rename.into());
        self
    }

    /// Get the dependency name as defined in the manifest,
    /// that is, either the alias (rename field if Some),
    /// or the official package name (name field).
    pub fn name_in_manifest(&self) -> &str {
        self.rename().unwrap_or(&self.name)
    }

    /// Set the value of registry for the dependency
    pub fn set_registry(mut self, registry: &str) -> Dependency {
        let old_version = match self.source {
            DependencySource::Version { version, .. } => version,
            _ => None,
        };
        self.source = DependencySource::Version {
            version: old_version,
            path: None,
            registry: Some(registry.into()),
        };
        self
    }

    /// Get version of dependency
    pub fn version(&self) -> Option<&str> {
        if let DependencySource::Version {
            version: Some(ref version),
            ..
        } = self.source
        {
            Some(version)
        } else {
            None
        }
    }

    /// Get the path of the dependency
    pub fn path(&self) -> Option<&Path> {
        if let DependencySource::Version {
            path: Some(ref path),
            ..
        } = self.source
        {
            Some(path.as_path())
        } else {
            None
        }
    }

    /// Get the alias for the dependency (if any)
    pub fn rename(&self) -> Option<&str> {
        self.rename.as_deref()
    }

    /// Convert dependency to TOML
    ///
    /// Returns a tuple with the dependency's name and either the version as a `String`
    /// or the path/git repository as an `InlineTable`.
    /// (If the dependency is set as `optional` or `default-features` is set to `false`,
    /// an `InlineTable` is returned in any case.)
    ///
    /// # Panic
    ///
    /// Panics if the path is relative
    pub fn to_toml(&self, crate_root: &Path) -> (String, toml_edit::Item) {
        assert!(
            crate_root.is_absolute(),
            "Absolute path needed, got: {}",
            crate_root.display()
        );
        let data: toml_edit::Item = match (
            self.optional,
            self.features.as_ref(),
            self.default_features,
            self.source.clone(),
            self.rename.as_ref(),
        ) {
            // Extra short when version flag only
            (
                false,
                None,
                true,
                DependencySource::Version {
                    version: Some(v),
                    path: None,
                    registry: None,
                },
                None,
            ) => toml_edit::value(v),
            // Other cases are represented as an inline table
            (optional, features, default_features, source, rename) => {
                let mut data = toml_edit::InlineTable::default();

                match source {
                    DependencySource::Version {
                        version,
                        path,
                        registry,
                    } => {
                        if let Some(v) = version {
                            data.get_or_insert("version", v);
                        }
                        if let Some(p) = path {
                            let relpath = pathdiff::diff_paths(p, crate_root)
                                .expect("both paths are absolute");
                            let relpath = relpath.to_str().unwrap().replace('\\', "/");
                            data.get_or_insert("path", relpath);
                        }
                        if let Some(r) = registry {
                            data.get_or_insert("registry", r);
                        }
                    }
                    DependencySource::Git {
                        repo,
                        branch,
                        tag,
                        rev,
                    } => {
                        data.get_or_insert("git", repo);
                        if let Some(branch) = branch {
                            data.get_or_insert("branch", branch);
                        }
                        if let Some(tag) = tag {
                            data.get_or_insert("tag", tag);
                        }
                        if let Some(rev) = rev {
                            data.get_or_insert("rev", rev);
                        }
                    }
                }
                if self.optional {
                    data.get_or_insert("optional", optional);
                }
                if let Some(features) = features {
                    let features: toml_edit::Value = features.iter().cloned().collect();
                    data.get_or_insert("features", features);
                }
                if !self.default_features {
                    data.get_or_insert("default-features", default_features);
                }
                if rename.is_some() {
                    data.get_or_insert("package", self.name.clone());
                }

                data.fmt();
                toml_edit::value(toml_edit::Value::InlineTable(data))
            }
        };

        (self.name_in_manifest().to_string(), data)
    }
}

impl Default for Dependency {
    fn default() -> Dependency {
        Dependency {
            name: "".into(),
            rename: None,
            optional: false,
            features: None,
            default_features: true,
            source: DependencySource::Version {
                version: None,
                path: None,
                registry: None,
            },
            available_features: vec![],
        }
    }
}

#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone)]
enum DependencySource {
    Version {
        version: Option<String>,
        path: Option<PathBuf>,
        registry: Option<String>,
    },
    Git {
        repo: String,
        branch: Option<String>,
        tag: Option<String>,
        rev: Option<String>,
    },
}

#[cfg(test)]
mod tests {
    use crate::dependency::Dependency;
    use std::path::Path;

    #[test]
    fn to_toml_simple_dep() {
        let crate_root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let dep = Dependency::new("dep");
        let (key, _item) = dep.to_toml(&crate_root);

        assert_eq!(key, "dep".to_owned());
    }

    #[test]
    fn to_toml_simple_dep_with_version() {
        let crate_root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let dep = Dependency::new("dep").set_version("1.0");
        let (key, item) = dep.to_toml(&crate_root);

        assert_eq!(key, "dep".to_owned());
        assert_eq!(item.as_str(), Some("1.0"));
    }

    #[test]
    fn to_toml_optional_dep() {
        let crate_root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let dep = Dependency::new("dep").set_optional(true);
        let (key, item) = dep.to_toml(&crate_root);

        assert_eq!(key, "dep".to_owned());
        assert!(item.is_inline_table());

        let dep = item.as_inline_table().unwrap();
        assert_eq!(dep.get("optional").unwrap().as_bool(), Some(true));
    }

    #[test]
    fn to_toml_dep_without_default_features() {
        let crate_root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let dep = Dependency::new("dep").set_default_features(false);
        let (key, item) = dep.to_toml(&crate_root);

        assert_eq!(key, "dep".to_owned());
        assert!(item.is_inline_table());

        let dep = item.as_inline_table().unwrap();
        assert_eq!(dep.get("default-features").unwrap().as_bool(), Some(false));
    }

    #[test]
    fn to_toml_dep_with_path_source() {
        let root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let crate_root = root.join("foo");
        let dep = Dependency::new("dep").set_path(root.join("bar"));
        let (key, item) = dep.to_toml(&crate_root);

        assert_eq!(key, "dep".to_owned());
        assert!(item.is_inline_table());

        let dep = item.as_inline_table().unwrap();
        assert_eq!(dep.get("path").unwrap().as_str(), Some("../bar"));
    }

    #[test]
    fn to_toml_dep_with_git_source() {
        let crate_root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let dep = Dependency::new("dep").set_git("https://foor/bar.git", None, None, None);
        let (key, item) = dep.to_toml(&crate_root);

        assert_eq!(key, "dep".to_owned());
        assert!(item.is_inline_table());

        let dep = item.as_inline_table().unwrap();
        assert_eq!(
            dep.get("git").unwrap().as_str(),
            Some("https://foor/bar.git")
        );
    }

    #[test]
    fn to_toml_renamed_dep() {
        let crate_root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let dep = Dependency::new("dep").set_rename("d");
        let (key, item) = dep.to_toml(&crate_root);

        assert_eq!(key, "d".to_owned());
        assert!(item.is_inline_table());

        let dep = item.as_inline_table().unwrap();
        assert_eq!(dep.get("package").unwrap().as_str(), Some("dep"));
    }

    #[test]
    fn to_toml_dep_from_alt_registry() {
        let crate_root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let dep = Dependency::new("dep").set_registry("alternative");
        let (key, item) = dep.to_toml(&crate_root);

        assert_eq!(key, "dep".to_owned());
        assert!(item.is_inline_table());

        let dep = item.as_inline_table().unwrap();
        assert_eq!(dep.get("registry").unwrap().as_str(), Some("alternative"));
    }

    #[test]
    fn to_toml_complex_dep() {
        let crate_root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let dep = Dependency::new("dep")
            .set_version("1.0")
            .set_default_features(false)
            .set_rename("d");
        let (key, item) = dep.to_toml(&crate_root);

        assert_eq!(key, "d".to_owned());
        assert!(item.is_inline_table());

        let dep = item.as_inline_table().unwrap();
        assert_eq!(dep.get("package").unwrap().as_str(), Some("dep"));
        assert_eq!(dep.get("version").unwrap().as_str(), Some("1.0"));
        assert_eq!(dep.get("default-features").unwrap().as_bool(), Some(false));
    }

    #[test]
    fn paths_with_forward_slashes_are_left_as_is() {
        let crate_root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let path = crate_root.join("sibling/crate");
        let relpath = "sibling/crate";
        let dep = Dependency::new("dep").set_path(path);
        let (_key, item) = dep.to_toml(&crate_root);

        let table = item.as_inline_table().unwrap();
        let got = table.get("path").unwrap().as_str().unwrap();
        assert_eq!(got, relpath);
    }

    #[test]
    #[cfg(windows)]
    fn normalise_windows_style_paths() {
        let crate_root = dunce::canonicalize(Path::new("/")).expect("root exists");
        let original = crate_root.join(r"sibling\crate");
        let should_be = "sibling/crate";
        let dep = Dependency::new("dep").set_path(original);
        let (key, item) = dep.to_toml(&crate_root);

        let table = item.as_inline_table().unwrap();
        let got = table.get("path").unwrap().as_str().unwrap();
        assert_eq!(got, should_be);
    }
}
<|endoftext|>


<commit_before>use xml::reader::{EventReader, XmlEvent};
use syntect::easy::HighlightLines;

#[derive(Debug)]
enum State {
  NotInBlock,
  MaybeStartBlock,
  Block(String),  // TODO: should it be `String` or `&str`?
  Failure(String),
}

#[derive(Debug)]
enum Event {
  StartPre,
  StartCode,
  EndCode,
  Other(String),  // TODO: &str? Something else?
}

impl State {
  fn next(self, event: Event) -> State {
    match (self, event) {
      (State::NotInBlock, Event::StartPre) => State::MaybeStartBlock,
      (State::MaybeStartBlock, Event::StartCode) =>
        State::Block(String::with_capacity(1000)),
      (State::Block(string), Event::Other(contents)) =>
        State::Block(string + &contents),
      (State::Block(string), Event::EndCode) => {
        // TODO: do something with the data here!
        State::NotInBlock
      },
      (s, e) => State::Failure(format!("Invalid state/event: {:?} | {:?}", s, e)),
    }
  }
}

pub fn syntax_highlight(html_string: String) -> String {
  let events = EventReader::from_str(&html_string).into_iter();
  let updated = events.map(|event| {
    match event {
      Ok(XmlEvent::StartElement { name, .. }) => {}
      Ok(XmlEvent::EndElement { name, .. }) => {}
      Err(_) => {
        println!(":wat: error parsing XML");
        {}
      },
      _ => {}
    }
  });
  String::new()  // TODO: actually build this, obviously
}
<commit_msg>Glob state machine enums to improve readability.<commit_after>use xml::reader::{EventReader, XmlEvent};
use syntect::easy::HighlightLines;

#[derive(Debug)]
enum State {
  NotInBlock,
  MaybeStartBlock,
  Block(String),  // TODO: should it be `String` or `&str`?
  Failure(String),
}

#[derive(Debug)]
enum Event {
  StartPre,
  StartCode,
  EndCode,
  Other(String),  // TODO: &str? Something else?
}

impl State {
  fn next(self, event: Event) -> State {
    use State::*;
    use Event::*;

    match (self, event) {
      (NotInBlock, StartPre) => MaybeStartBlock,
      (MaybeStartBlock, StartCode) =>
        Block(String::with_capacity(1000)),
      (Block(string), Other(contents)) =>
        Block(string + &contents),
      (Block(string), EndCode) => {
        // TODO: do something with the data here!
        State::NotInBlock
      },
      (s, e) => State::Failure(format!("Invalid state/event: {:?} | {:?}", s, e)),
    }
  }
}

pub fn syntax_highlight(html_string: String) -> String {
  let events = EventReader::from_str(&html_string).into_iter();
  let updated = events.map(|event| {
    match event {
      Ok(XmlEvent::StartElement { name, .. }) => {}
      Ok(XmlEvent::EndElement { name, .. }) => {}
      Err(_) => {
        println!(":wat: error parsing XML");
        {}
      },
      _ => {}
    }
  });
  String::new()  // TODO: actually build this, obviously
}
<|endoftext|>


<commit_before>use self::StartsWithStateInternal::*;

/// Automaton describes types that behave as a finite automaton.
///
/// All implementors of this trait are represented by *byte based* automata.
/// Stated differently, all transitions in the automata correspond to a single
/// byte in the input.
///
/// This implementation choice is important for a couple reasons:
///
/// 1. The set of possible transitions in each node is small, which may make
///    efficient memory usage easier.
/// 2. The finite state transducers in this crate are all byte based, so any
///    automata used on them must also be byte based.
///
/// In practice, this does present somewhat of a problem, for example, if
/// you're storing UTF-8 encoded strings in a finite state transducer. Consider
/// using a `Levenshtein` automaton, which accepts a query string and an edit
/// distance. The edit distance should apply to some notion of *character*,
/// which could be represented by at least 1-4 bytes in a UTF-8 encoding (for
/// some definition of "character"). Therefore, the automaton must have UTF-8
/// decoding built into it. This can be tricky to implement, so you may find
/// the [`utf8-ranges`](https://crates.io/crates/utf8-ranges) crate useful.
pub trait Automaton {
    /// The type of the state used in the automaton.
    type State;

    /// Returns a single start state for this automaton.
    ///
    /// This method should always return the same value for each
    /// implementation.
    fn start(&self) -> Self::State;

    /// Returns true if and only if `state` is a match state.
    fn is_match(&self, state: &Self::State) -> bool;

    /// Returns true if and only if `state` can lead to a match in zero or more
    /// steps.
    ///
    /// If this returns `false`, then no sequence of inputs from this state
    /// should ever produce a match. If this does not follow, then those match
    /// states may never be reached. In other words, behavior may be incorrect.
    ///
    /// If this returns `true` even when no match is possible, then behavior
    /// will be correct, but callers may be forced to do additional work.
    fn can_match(&self, _state: &Self::State) -> bool {
        true
    }

    /// Returns true if and only if `state` matches and must match no matter
    /// what steps are taken.
    ///
    /// If this returns `true`, then every sequence of inputs from this state
    /// produces a match. If this does not follow, then those match states may
    /// never be reached. In other words, behavior may be incorrect.
    ///
    /// If this returns `false` even when every sequence of inputs will lead to
    /// a match, then behavior will be correct, but callers may be forced to do
    /// additional work.
    fn will_always_match(&self, _state: &Self::State) -> bool {
        false
    }

    /// Return the next state given `state` and an input.
    fn accept(&self, state: &Self::State, byte: u8) -> Self::State;

    /// Returns an automaton that matches the strings that start with something
    /// this automaton matches.
    fn starts_with(self) -> StartsWith<Self> where Self: Sized {
        StartsWith(self)
    }

    /// Returns an automaton that matches the strings matched by either this or
    /// the other automaton.
    fn union<Rhs: Automaton>(
        self,
        rhs: Rhs,
    ) -> Union<Self, Rhs> where Self: Sized {
        Union(self, rhs)
    }

    /// Returns an automaton that matches the strings matched by both this and
    /// the other automaton.
    fn intersection<Rhs: Automaton>(
        self,
        rhs: Rhs,
    ) -> Intersection<Self, Rhs> where Self: Sized {
        Intersection(self, rhs)
    }

    /// Returns an automaton that matches the strings not matched by this
    /// automaton.
    fn complement(self) -> Complement<Self> where Self: Sized {
        Complement(self)
    }
}

impl<'a, T: Automaton> Automaton for &'a T {
    type State = T::State;

    fn start(&self) -> Self::State {
        (*self).start()
    }

    fn is_match(&self, state: &Self::State) -> bool {
        (*self).is_match(state)
    }

    fn can_match(&self, state: &Self::State) -> bool {
        (*self).can_match(state)
    }

    fn will_always_match(&self, state: &Self::State) -> bool {
        (*self).will_always_match(state)
    }

    fn accept(&self, state: &Self::State, byte: u8) -> Self::State {
        (*self).accept(state, byte)
    }
}

/// An automaton that matches if the input contains a specific subsequence.
///
/// It can be used to build a simple fuzzy-finder.
///
/// ```rust
/// extern crate fst;
///
/// use std::error::Error;
///
/// use fst::{IntoStreamer, Streamer, Set};
/// use fst::automaton::Subsequence;
///
/// # fn main() { example().unwrap(); }
/// fn example() -> Result<(), Box<Error>> {
///     let paths = vec!["/home/projects/bar", "/home/projects/foo", "/tmp/foo"];
///     let set = Set::from_iter(paths)?;
///
///     // Build our fuzzy query.
///     let subseq = Subsequence::new("hpf");
///
///     // Apply our fuzzy query to the set we built.
///     let mut stream = set.search(subseq).into_stream();
///
///     let matches = stream.into_strs()?;
///     assert_eq!(matches, vec!["/home/projects/foo"]);
///     Ok(())
/// }
/// ```
pub struct Subsequence<'a> {
    subseq: &'a [u8]
}

impl<'a> Subsequence<'a> {
    /// Constructs automaton that matches input containing the
    /// specified subsequence.
    pub fn new(subsequence: &'a str) -> Subsequence<'a> {
        Subsequence { subseq: subsequence.as_bytes() }
    }
}

impl<'a> Automaton for Subsequence<'a> {
    type State = usize;

    fn start(&self) -> usize { 0 }

    fn is_match(&self, &state: &usize) -> bool {
        state == self.subseq.len()
    }

    fn can_match(&self, _: &usize) -> bool { true }

    fn will_always_match(&self, &state: &usize) -> bool {
        state == self.subseq.len()
    }

    fn accept(&self, &state: &usize, byte: u8) -> usize {
        if state == self.subseq.len() { return state; }
        state + (byte == self.subseq[state]) as usize
    }
}

/// An automaton that always matches.
///
/// This is useful in a generic context as a way to express that no automaton
/// should be used.
pub struct AlwaysMatch;

impl Automaton for AlwaysMatch {
    type State = ();

    fn start(&self) -> () { () }
    fn is_match(&self, _: &()) -> bool { true }
    fn can_match(&self, _: &()) -> bool { true }
    fn will_always_match(&self, _: &()) -> bool { true }
    fn accept(&self, _: &(), _: u8) -> () { () }
}

/// An automaton that matches a string that begins with something that the
/// wrapped automaton matches.
pub struct StartsWith<A>(A);

/// The `Automaton` state for `StartsWith<A>`.
pub struct StartsWithState<A: Automaton>(StartsWithStateInternal<A>);

enum StartsWithStateInternal<A: Automaton> {
    Done,
    Running(A::State)
}

impl<A: Automaton> Automaton for StartsWith<A> {
    type State = StartsWithState<A>;
    fn start(&self) -> StartsWithState<A> {
        StartsWithState({
            let inner = self.0.start();
            if self.0.is_match(&inner) {
                Done
            } else {
                Running(inner)
            }
        })
    }

    fn is_match(&self, state: &StartsWithState<A>) -> bool {
        match state.0 {
            Done => true,
            Running(_) => false
        }
    }

    fn can_match(&self, state: &StartsWithState<A>) -> bool {
        match state.0 {
            Done => true,
            Running(ref inner) => self.0.can_match(inner)
        }
    }

    fn will_always_match(&self, state: &StartsWithState<A>) -> bool {
        match state.0 {
            Done => true,
            Running(_) => false
        }
    }

    fn accept(
        &self,
        state: &StartsWithState<A>,
        byte: u8,
    ) -> StartsWithState<A> {
        StartsWithState(
            match state.0 {
                Done => Done,
                Running(ref inner) => {
                    let next_inner = self.0.accept(inner, byte);
                    if self.0.is_match(&next_inner) {
                        Done
                    } else {
                        Running(next_inner)
                    }
                }
            }
        )
    }
}

/// An automaton that matches when one of its component automata match.
pub struct Union<A, B>(A, B);

/// The `Automaton` state for `Union<A, B>`.
pub struct UnionState<A: Automaton, B: Automaton>(A::State, B::State);

impl<A: Automaton, B: Automaton> Automaton for Union<A, B> {
    type State = UnionState<A, B>;

    fn start(&self) -> UnionState<A, B> {
        UnionState(
            self.0.start(),
            self.1.start()
        )
    }

    fn is_match(&self, state: &UnionState<A, B>) -> bool {
        self.0.is_match(&state.0) || self.1.is_match(&state.1)
    }

    fn can_match(&self, state: &UnionState<A, B>) -> bool {
        self.0.can_match(&state.0) || self.1.can_match(&state.1)
    }

    fn will_always_match(&self, state: &UnionState<A, B>) -> bool {
        self.0.will_always_match(&state.0)
        || self.1.will_always_match(&state.1)
    }

    fn accept(&self, state: &UnionState<A, B>, byte: u8) -> UnionState<A, B> {
        UnionState(
            self.0.accept(&state.0, byte),
            self.1.accept(&state.1, byte)
        )
    }
}

/// An automaton that matches when both of its component automata match.
pub struct Intersection<A, B>(A, B);

/// The `Automaton` state for `Intersection<A, B>`.
pub struct IntersectionState<A: Automaton, B: Automaton>(A::State, B::State);

impl<A: Automaton, B: Automaton> Automaton for Intersection<A, B> {
    type State = IntersectionState<A, B>;

    fn start(&self) -> IntersectionState<A, B> {
        IntersectionState(
            self.0.start(),
            self.1.start()
        )
    }

    fn is_match(&self, state: &IntersectionState<A, B>) -> bool {
        self.0.is_match(&state.0) && self.1.is_match(&state.1)
    }

    fn can_match(&self, state: &IntersectionState<A, B>) -> bool {
        self.0.can_match(&state.0) && self.1.can_match(&state.1)
    }

    fn will_always_match(&self, state: &IntersectionState<A, B>) -> bool {
        self.0.will_always_match(&state.0) && self.1.will_always_match(&state.1)
    }

    fn accept(
        &self,
        state: &IntersectionState<A, B>,
        byte: u8,
    ) -> IntersectionState<A, B> {
        IntersectionState(
            self.0.accept(&state.0, byte),
            self.1.accept(&state.1, byte)
        )
    }
}

/// An automaton that matches exactly when the automaton it wraps does not.
pub struct Complement<A>(A);

/// The `Automaton` state for `Complement<A>`.
pub struct ComplementState<A: Automaton>(A::State);

impl<A: Automaton> Automaton for Complement<A> {
    type State = ComplementState<A>;

    fn start(&self) -> ComplementState<A> {
        ComplementState(self.0.start())
    }

    fn is_match(&self, state: &ComplementState<A>) -> bool {
        !self.0.is_match(&state.0)
    }

    fn can_match(&self, state: &ComplementState<A>) -> bool {
        !self.0.will_always_match(&state.0)
    }

    fn will_always_match(&self, state: &ComplementState<A>) -> bool {
        !self.0.can_match(&state.0)
    }

    fn accept(
        &self,
        state: &ComplementState<A>,
        byte: u8,
    ) -> ComplementState<A> {
        ComplementState(self.0.accept(&state.0, byte))
    }
}
<commit_msg>subsequence: derive common traits<commit_after>use self::StartsWithStateInternal::*;

/// Automaton describes types that behave as a finite automaton.
///
/// All implementors of this trait are represented by *byte based* automata.
/// Stated differently, all transitions in the automata correspond to a single
/// byte in the input.
///
/// This implementation choice is important for a couple reasons:
///
/// 1. The set of possible transitions in each node is small, which may make
///    efficient memory usage easier.
/// 2. The finite state transducers in this crate are all byte based, so any
///    automata used on them must also be byte based.
///
/// In practice, this does present somewhat of a problem, for example, if
/// you're storing UTF-8 encoded strings in a finite state transducer. Consider
/// using a `Levenshtein` automaton, which accepts a query string and an edit
/// distance. The edit distance should apply to some notion of *character*,
/// which could be represented by at least 1-4 bytes in a UTF-8 encoding (for
/// some definition of "character"). Therefore, the automaton must have UTF-8
/// decoding built into it. This can be tricky to implement, so you may find
/// the [`utf8-ranges`](https://crates.io/crates/utf8-ranges) crate useful.
pub trait Automaton {
    /// The type of the state used in the automaton.
    type State;

    /// Returns a single start state for this automaton.
    ///
    /// This method should always return the same value for each
    /// implementation.
    fn start(&self) -> Self::State;

    /// Returns true if and only if `state` is a match state.
    fn is_match(&self, state: &Self::State) -> bool;

    /// Returns true if and only if `state` can lead to a match in zero or more
    /// steps.
    ///
    /// If this returns `false`, then no sequence of inputs from this state
    /// should ever produce a match. If this does not follow, then those match
    /// states may never be reached. In other words, behavior may be incorrect.
    ///
    /// If this returns `true` even when no match is possible, then behavior
    /// will be correct, but callers may be forced to do additional work.
    fn can_match(&self, _state: &Self::State) -> bool {
        true
    }

    /// Returns true if and only if `state` matches and must match no matter
    /// what steps are taken.
    ///
    /// If this returns `true`, then every sequence of inputs from this state
    /// produces a match. If this does not follow, then those match states may
    /// never be reached. In other words, behavior may be incorrect.
    ///
    /// If this returns `false` even when every sequence of inputs will lead to
    /// a match, then behavior will be correct, but callers may be forced to do
    /// additional work.
    fn will_always_match(&self, _state: &Self::State) -> bool {
        false
    }

    /// Return the next state given `state` and an input.
    fn accept(&self, state: &Self::State, byte: u8) -> Self::State;

    /// Returns an automaton that matches the strings that start with something
    /// this automaton matches.
    fn starts_with(self) -> StartsWith<Self> where Self: Sized {
        StartsWith(self)
    }

    /// Returns an automaton that matches the strings matched by either this or
    /// the other automaton.
    fn union<Rhs: Automaton>(
        self,
        rhs: Rhs,
    ) -> Union<Self, Rhs> where Self: Sized {
        Union(self, rhs)
    }

    /// Returns an automaton that matches the strings matched by both this and
    /// the other automaton.
    fn intersection<Rhs: Automaton>(
        self,
        rhs: Rhs,
    ) -> Intersection<Self, Rhs> where Self: Sized {
        Intersection(self, rhs)
    }

    /// Returns an automaton that matches the strings not matched by this
    /// automaton.
    fn complement(self) -> Complement<Self> where Self: Sized {
        Complement(self)
    }
}

impl<'a, T: Automaton> Automaton for &'a T {
    type State = T::State;

    fn start(&self) -> Self::State {
        (*self).start()
    }

    fn is_match(&self, state: &Self::State) -> bool {
        (*self).is_match(state)
    }

    fn can_match(&self, state: &Self::State) -> bool {
        (*self).can_match(state)
    }

    fn will_always_match(&self, state: &Self::State) -> bool {
        (*self).will_always_match(state)
    }

    fn accept(&self, state: &Self::State, byte: u8) -> Self::State {
        (*self).accept(state, byte)
    }
}

/// An automaton that matches if the input contains a specific subsequence.
///
/// It can be used to build a simple fuzzy-finder.
///
/// ```rust
/// extern crate fst;
///
/// use std::error::Error;
///
/// use fst::{IntoStreamer, Streamer, Set};
/// use fst::automaton::Subsequence;
///
/// # fn main() { example().unwrap(); }
/// fn example() -> Result<(), Box<Error>> {
///     let paths = vec!["/home/projects/bar", "/home/projects/foo", "/tmp/foo"];
///     let set = Set::from_iter(paths)?;
///
///     // Build our fuzzy query.
///     let subseq = Subsequence::new("hpf");
///
///     // Apply our fuzzy query to the set we built.
///     let mut stream = set.search(subseq).into_stream();
///
///     let matches = stream.into_strs()?;
///     assert_eq!(matches, vec!["/home/projects/foo"]);
///     Ok(())
/// }
/// ```
#[derive(Clone, Copy, Debug)]
pub struct Subsequence<'a> {
    subseq: &'a [u8]
}

impl<'a> Subsequence<'a> {
    /// Constructs automaton that matches input containing the
    /// specified subsequence.
    pub fn new(subsequence: &'a str) -> Subsequence<'a> {
        Subsequence { subseq: subsequence.as_bytes() }
    }
}

impl<'a> Automaton for Subsequence<'a> {
    type State = usize;

    fn start(&self) -> usize { 0 }

    fn is_match(&self, &state: &usize) -> bool {
        state == self.subseq.len()
    }

    fn can_match(&self, _: &usize) -> bool { true }

    fn will_always_match(&self, &state: &usize) -> bool {
        state == self.subseq.len()
    }

    fn accept(&self, &state: &usize, byte: u8) -> usize {
        if state == self.subseq.len() { return state; }
        state + (byte == self.subseq[state]) as usize
    }
}

/// An automaton that always matches.
///
/// This is useful in a generic context as a way to express that no automaton
/// should be used.
pub struct AlwaysMatch;

impl Automaton for AlwaysMatch {
    type State = ();

    fn start(&self) -> () { () }
    fn is_match(&self, _: &()) -> bool { true }
    fn can_match(&self, _: &()) -> bool { true }
    fn will_always_match(&self, _: &()) -> bool { true }
    fn accept(&self, _: &(), _: u8) -> () { () }
}

/// An automaton that matches a string that begins with something that the
/// wrapped automaton matches.
pub struct StartsWith<A>(A);

/// The `Automaton` state for `StartsWith<A>`.
pub struct StartsWithState<A: Automaton>(StartsWithStateInternal<A>);

enum StartsWithStateInternal<A: Automaton> {
    Done,
    Running(A::State)
}

impl<A: Automaton> Automaton for StartsWith<A> {
    type State = StartsWithState<A>;
    fn start(&self) -> StartsWithState<A> {
        StartsWithState({
            let inner = self.0.start();
            if self.0.is_match(&inner) {
                Done
            } else {
                Running(inner)
            }
        })
    }

    fn is_match(&self, state: &StartsWithState<A>) -> bool {
        match state.0 {
            Done => true,
            Running(_) => false
        }
    }

    fn can_match(&self, state: &StartsWithState<A>) -> bool {
        match state.0 {
            Done => true,
            Running(ref inner) => self.0.can_match(inner)
        }
    }

    fn will_always_match(&self, state: &StartsWithState<A>) -> bool {
        match state.0 {
            Done => true,
            Running(_) => false
        }
    }

    fn accept(
        &self,
        state: &StartsWithState<A>,
        byte: u8,
    ) -> StartsWithState<A> {
        StartsWithState(
            match state.0 {
                Done => Done,
                Running(ref inner) => {
                    let next_inner = self.0.accept(inner, byte);
                    if self.0.is_match(&next_inner) {
                        Done
                    } else {
                        Running(next_inner)
                    }
                }
            }
        )
    }
}

/// An automaton that matches when one of its component automata match.
pub struct Union<A, B>(A, B);

/// The `Automaton` state for `Union<A, B>`.
pub struct UnionState<A: Automaton, B: Automaton>(A::State, B::State);

impl<A: Automaton, B: Automaton> Automaton for Union<A, B> {
    type State = UnionState<A, B>;

    fn start(&self) -> UnionState<A, B> {
        UnionState(
            self.0.start(),
            self.1.start()
        )
    }

    fn is_match(&self, state: &UnionState<A, B>) -> bool {
        self.0.is_match(&state.0) || self.1.is_match(&state.1)
    }

    fn can_match(&self, state: &UnionState<A, B>) -> bool {
        self.0.can_match(&state.0) || self.1.can_match(&state.1)
    }

    fn will_always_match(&self, state: &UnionState<A, B>) -> bool {
        self.0.will_always_match(&state.0)
        || self.1.will_always_match(&state.1)
    }

    fn accept(&self, state: &UnionState<A, B>, byte: u8) -> UnionState<A, B> {
        UnionState(
            self.0.accept(&state.0, byte),
            self.1.accept(&state.1, byte)
        )
    }
}

/// An automaton that matches when both of its component automata match.
pub struct Intersection<A, B>(A, B);

/// The `Automaton` state for `Intersection<A, B>`.
pub struct IntersectionState<A: Automaton, B: Automaton>(A::State, B::State);

impl<A: Automaton, B: Automaton> Automaton for Intersection<A, B> {
    type State = IntersectionState<A, B>;

    fn start(&self) -> IntersectionState<A, B> {
        IntersectionState(
            self.0.start(),
            self.1.start()
        )
    }

    fn is_match(&self, state: &IntersectionState<A, B>) -> bool {
        self.0.is_match(&state.0) && self.1.is_match(&state.1)
    }

    fn can_match(&self, state: &IntersectionState<A, B>) -> bool {
        self.0.can_match(&state.0) && self.1.can_match(&state.1)
    }

    fn will_always_match(&self, state: &IntersectionState<A, B>) -> bool {
        self.0.will_always_match(&state.0) && self.1.will_always_match(&state.1)
    }

    fn accept(
        &self,
        state: &IntersectionState<A, B>,
        byte: u8,
    ) -> IntersectionState<A, B> {
        IntersectionState(
            self.0.accept(&state.0, byte),
            self.1.accept(&state.1, byte)
        )
    }
}

/// An automaton that matches exactly when the automaton it wraps does not.
pub struct Complement<A>(A);

/// The `Automaton` state for `Complement<A>`.
pub struct ComplementState<A: Automaton>(A::State);

impl<A: Automaton> Automaton for Complement<A> {
    type State = ComplementState<A>;

    fn start(&self) -> ComplementState<A> {
        ComplementState(self.0.start())
    }

    fn is_match(&self, state: &ComplementState<A>) -> bool {
        !self.0.is_match(&state.0)
    }

    fn can_match(&self, state: &ComplementState<A>) -> bool {
        !self.0.will_always_match(&state.0)
    }

    fn will_always_match(&self, state: &ComplementState<A>) -> bool {
        !self.0.can_match(&state.0)
    }

    fn accept(
        &self,
        state: &ComplementState<A>,
        byte: u8,
    ) -> ComplementState<A> {
        ComplementState(self.0.accept(&state.0, byte))
    }
}
<|endoftext|>