<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()) 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 => {
					if chunk_len != MAGIC_BODY.len() {
						return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"))
					}

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

					// Check Written Buffer
					for (m, b) in MAGIC_BODY.iter().zip(self.buf.iter()) {
						if m != b {
							return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"))
						}
					}

					continue;
				},

				// 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>Write-out a Decompressor Port<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 => {
					if chunk_len != MAGIC_BODY.len() {
						return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"))
					}

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

					// Check Written Buffer
					for (m, b) in MAGIC_BODY.iter().zip(self.buf.iter()) {
						if m != b {
							return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"))
						}
					}

					continue;
				},

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

			}

			// Section 4.4 Padding (chunk type 0xfe).
			// Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd).
			if self.inner.read(self.buf.split_at_mut(chunk_len).0).unwrap() != chunk_len {
				return Err(Error::new(ErrorKind::InvalidInput, "snappy: corrupt input"))
			}

		}
	}
}

// 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>// Copyright 2013 The noise-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! An example of using simplex noise

#![feature(macro_rules)]

extern crate noise;

use noise::{open_simplex2, open_simplex3, Seed, Point2};

mod debug;

fn main() {
    debug::render_png("open_simplex2.png", &Seed::new(0), 256, 256, scaled_open_simplex2);
    debug::render_png("open_simplex3.png", &Seed::new(0), 256, 256, scaled_open_simplex3);
    println!("\nGenerated simplex2.png and simplex3.png");
}

fn scaled_open_simplex2(seed: &Seed, point: &Point2<f32>) -> f32 {
    open_simplex2(seed, &[point[0] / 32.0, point[1] / 32.00])
}

fn scaled_open_simplex3(seed: &Seed, point: &Point2<f32>) -> f32 {
    open_simplex3(seed, &[point[0] / 32.0, point[1] / 32.00, 0.0])
}
<commit_msg>Correctly name the files created by the open_simplex example.<commit_after>// Copyright 2015 The noise-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! An example of using simplex noise

#![feature(macro_rules)]

extern crate noise;

use noise::{open_simplex2, open_simplex3, Seed, Point2};

mod debug;

fn main() {
    debug::render_png("open_simplex2.png", &Seed::new(0), 256, 256, scaled_open_simplex2);
    debug::render_png("open_simplex3.png", &Seed::new(0), 256, 256, scaled_open_simplex3);
    println!("\nGenerated open_simplex2.png and open_simplex3.png");
}

fn scaled_open_simplex2(seed: &Seed, point: &Point2<f32>) -> f32 {
    open_simplex2(seed, &[point[0] / 32.0, point[1] / 32.00])
}

fn scaled_open_simplex3(seed: &Seed, point: &Point2<f32>) -> f32 {
    open_simplex3(seed, &[point[0] / 32.0, point[1] / 32.00, 0.0])
}
<|endoftext|>


<commit_before>use Login;
use FromJson;
use post_json;

use std::collections::HashMap;
use json::JsonValue;

pub fn get_courses(login: &Login) -> Option<Vec<Course>> {
    let url = "https://wwwqis.htw-dresden.de/appservice/getcourses";
    let mut map = HashMap::new();
    map.insert("sNummer", login.snumber.clone()); // is cloning ok?
    map.insert("RZLogin", login.password.clone());

    let json = post_json(url, map);
    let courses = Course::mult_from_json(json);
    Some(courses)
}

#[derive(Debug)]
pub struct Course {
    pub degree_txt: String,
    pub reg_version: String,
    pub deg_nr: String,
    pub course_nr: String,
    pub course_note: String,
}

impl FromJson for Course {
    fn from_json(json: JsonValue) -> Self {
        Course {
            degree_txt: String::from(json["AbschlTxt"].as_str().unwrap()),
            reg_version: String::from(json["POVersion"].as_str().unwrap()),
            deg_nr: String::from(json["AbschlNr"].as_str().unwrap()),
            course_nr: String::from(json["StgNr"].as_str().unwrap()),
            course_note: String::from(json["StgTxt"].as_str().unwrap()),
        }
    }
}

pub fn get_grades(login: &Login, course: &Course) -> Option<Vec<Grade>> {
    let url = "https://wwwqis.htw-dresden.de/appservice/getgrades";
    let mut map = HashMap::new();
    map.insert("sNummer", login.snumber.clone());
    map.insert("RZLogin", login.password.clone());
    map.insert("AbschlNr", course.deg_nr.clone());
    map.insert("StgNr", course.course_nr.clone());
    map.insert("POVersion", course.reg_version.clone());

    let json = post_json(url, map);
    let grades = Grade::mult_from_json(json);
    Some(grades)
}

#[derive(Debug)]
pub struct Grade {
    pub exam_nr: String,
    pub status: String,
    pub ects_credits: String,
    pub exam_txt: String,
    pub semester: String,
    pub try_count: String,
    pub exam_date: String,
    pub grade: String,
    pub publish_date: String,
    pub exam_form: String,
    pub comment: String,
    pub ects_grade: String,
}

impl FromJson for Grade {
    fn from_json(json: JsonValue) -> Self {
        Grade {
            exam_nr: String::from(json["PrNr"].as_str().unwrap()),
            status: String::from(json["Status"].as_str().unwrap()),
            ects_credits: String::from(json["EctsCredits"].as_str().unwrap()),
            exam_txt: String::from(json["PrTxt"].as_str().unwrap()),
            semester: String::from(json["Semester"].as_str().unwrap()),
            try_count: String::from(json["Versuch"].as_str().unwrap()),
            exam_date: String::from(json["PrDatum"].as_str().unwrap()),
            grade: String::from(json["PrNote"].as_str().unwrap()),
            publish_date: String::from(json["VoDatum"].as_str().unwrap()),
            exam_form: String::from(json["PrForm"].as_str().unwrap()),
            comment: String::from(json["Vermerk"].as_str().unwrap()),
            ects_grade: String::from(json["EctsGrade"].as_str().unwrap()),
        }
    }
}
<commit_msg>document get_courses and get_grades()<commit_after>use Login;
use FromJson;
use post_json;

use std::collections::HashMap;
use json::JsonValue;

/// Returns a list of courses for a given login.
///
/// # Arguments
///
/// * `login` - Login
///
/// # Example
///
/// ```
/// use htwdresden::{Login, grades}
///
/// let login = Login::new("s#####", "password");
/// let courses = grades::get_courses(&login);
/// ```
pub fn get_courses(login: &Login) -> Option<Vec<Course>> {
    let url = "https://wwwqis.htw-dresden.de/appservice/getcourses";
    let mut map = HashMap::new();
    map.insert("sNummer", login.snumber.clone()); // is cloning ok?
    map.insert("RZLogin", login.password.clone());

    let json = post_json(url, map);
    let courses = Course::mult_from_json(json);
    Some(courses)
}

#[derive(Debug)]
pub struct Course {
    pub degree_txt: String,
    pub reg_version: String,
    pub deg_nr: String,
    pub course_nr: String,
    pub course_note: String,
}

impl FromJson for Course {
    fn from_json(json: JsonValue) -> Self {
        Course {
            degree_txt: String::from(json["AbschlTxt"].as_str().unwrap()),
            reg_version: String::from(json["POVersion"].as_str().unwrap()),
            deg_nr: String::from(json["AbschlNr"].as_str().unwrap()),
            course_nr: String::from(json["StgNr"].as_str().unwrap()),
            course_note: String::from(json["StgTxt"].as_str().unwrap()),
        }
    }
}

/// Returns a list of grades for a given login and course.
///
/// # Arguments
///
/// * `login` - Login
/// * `course` - Course
///
/// # Example
///
/// ```
/// use htwdresden::{Login, Course, grades};
///
/// let login = Login::new("s#####", "password");
/// let courses = grades::get_courses(&login);
/// let all_grades = grades::get_grades(&login, &courses[0]);
/// ```
pub fn get_grades(login: &Login, course: &Course) -> Option<Vec<Grade>> {
    let url = "https://wwwqis.htw-dresden.de/appservice/getgrades";
    let mut map = HashMap::new();
    map.insert("sNummer", login.snumber.clone());
    map.insert("RZLogin", login.password.clone());
    map.insert("AbschlNr", course.deg_nr.clone());
    map.insert("StgNr", course.course_nr.clone());
    map.insert("POVersion", course.reg_version.clone());

    let json = post_json(url, map);
    let grades = Grade::mult_from_json(json);
    Some(grades)
}

#[derive(Debug)]
pub struct Grade {
    pub exam_nr: String,
    pub status: String,
    pub ects_credits: String,
    pub exam_txt: String,
    pub semester: String,
    pub try_count: String,
    pub exam_date: String,
    pub grade: String,
    pub publish_date: String,
    pub exam_form: String,
    pub comment: String,
    pub ects_grade: String,
}

impl FromJson for Grade {
    fn from_json(json: JsonValue) -> Self {
        Grade {
            exam_nr: String::from(json["PrNr"].as_str().unwrap()),
            status: String::from(json["Status"].as_str().unwrap()),
            ects_credits: String::from(json["EctsCredits"].as_str().unwrap()),
            exam_txt: String::from(json["PrTxt"].as_str().unwrap()),
            semester: String::from(json["Semester"].as_str().unwrap()),
            try_count: String::from(json["Versuch"].as_str().unwrap()),
            exam_date: String::from(json["PrDatum"].as_str().unwrap()),
            grade: String::from(json["PrNote"].as_str().unwrap()),
            publish_date: String::from(json["VoDatum"].as_str().unwrap()),
            exam_form: String::from(json["PrForm"].as_str().unwrap()),
            comment: String::from(json["Vermerk"].as_str().unwrap()),
            ects_grade: String::from(json["EctsGrade"].as_str().unwrap()),
        }
    }
}
<|endoftext|>


<commit_before>use serde::de::{Deserialize, Deserializer};

use crate::http::error::DiscordJsonSingleError;
use crate::internal::prelude::*;

#[allow(clippy::missing_errors_doc)]
pub fn deserialize_errors<'de, D: Deserializer<'de>>(
    deserializer: D,
) -> StdResult<Vec<DiscordJsonSingleError>, D::Error> {
    let map: Value = Value::deserialize(deserializer)?;

    if !map.is_object() {
        return Ok(vec![]);
    }

    let mut errors = Vec::new();

    loop_errors(&map, &mut errors, &[]);

    Ok(errors)
}

fn loop_errors(value: &Value, errors: &mut Vec<DiscordJsonSingleError>, path: &[String]) {
    for (key, looped) in value.as_object().expect("expected object").iter() {
        let object = looped.as_object().expect("expected object");
        if object.contains_key("_errors") {
            let found_errors = object
                .get("_errors")
                .expect("expected _errors")
                .as_array()
                .expect("expected array")
                .clone();

            // FIXME: This is a workaround to a bug in the {Create,Edit}ScheduledEvent endpoints.
            // Occasionally there will be an additional nested _errors field. See the relevant
            // github issue: https://github.com/discord/discord-api-docs/issues/4811
            let found_errors = match found_errors[0].get("_errors") {
                Some(array) => array.as_array().expect("expected array"),
                None => &found_errors,
            };

            for error in found_errors {
                let error_object = error.as_object().expect("expected object");
                let mut object_path = path.to_owned();

                object_path.push(key.to_string());

                errors.push(DiscordJsonSingleError {
                    code: error_object
                        .get("code")
                        .expect("expected code")
                        .as_str()
                        .expect("expected string")
                        .to_owned(),
                    message: error_object
                        .get("message")
                        .expect("expected message")
                        .as_str()
                        .expect("expected string")
                        .to_owned(),
                    path: object_path.join("."),
                });
            }
            continue;
        }

        let mut new_path = path.to_owned();
        new_path.push(key.to_string());

        loop_errors(looped, errors, &new_path);
    }
}
<commit_msg>Remove workaround for deserialization error in Scheduled Event endpoints (#2134)<commit_after>use serde::de::{Deserialize, Deserializer};

use crate::http::error::DiscordJsonSingleError;
use crate::internal::prelude::*;

#[allow(clippy::missing_errors_doc)]
pub fn deserialize_errors<'de, D: Deserializer<'de>>(
    deserializer: D,
) -> StdResult<Vec<DiscordJsonSingleError>, D::Error> {
    let map: Value = Value::deserialize(deserializer)?;

    if !map.is_object() {
        return Ok(vec![]);
    }

    let mut errors = Vec::new();

    loop_errors(&map, &mut errors, &[]);

    Ok(errors)
}

fn loop_errors(value: &Value, errors: &mut Vec<DiscordJsonSingleError>, path: &[String]) {
    for (key, looped) in value.as_object().expect("expected object").iter() {
        let object = looped.as_object().expect("expected object");
        if object.contains_key("_errors") {
            let found_errors = object
                .get("_errors")
                .expect("expected _errors")
                .as_array()
                .expect("expected array")
                .clone();

            for error in found_errors {
                let error_object = error.as_object().expect("expected object");
                let mut object_path = path.to_owned();

                object_path.push(key.to_string());

                errors.push(DiscordJsonSingleError {
                    code: error_object
                        .get("code")
                        .expect("expected code")
                        .as_str()
                        .expect("expected string")
                        .to_owned(),
                    message: error_object
                        .get("message")
                        .expect("expected message")
                        .as_str()
                        .expect("expected string")
                        .to_owned(),
                    path: object_path.join("."),
                });
            }
            continue;
        }

        let mut new_path = path.to_owned();
        new_path.push(key.to_string());

        loop_errors(looped, errors, &new_path);
    }
}
<|endoftext|>


<commit_before>//! Function interfaces for VST 2.4 API.

#![doc(hidden)]

use std::{mem, slice};
use std::cell::Cell;
use std::os::raw::{c_char, c_void};

use buffer::AudioBuffer;
use api::consts::*;
use api::{self, AEffect, TimeInfo};
use editor::{Key, KeyCode, KnobMode, Rect};
use host::Host;

/// Deprecated process function.
pub fn process_deprecated(
    _effect: *mut AEffect,
    _raw_inputs: *const *const f32,
    _raw_outputs: *mut *mut f32,
    _samples: i32,
) {
}

/// VST2.4 replacing function.
pub fn process_replacing(
    effect: *mut AEffect,
    raw_inputs: *const *const f32,
    raw_outputs: *mut *mut f32,
    samples: i32,
) {
    // Handle to the VST
    let plugin = unsafe { (*effect).get_plugin() };
    let cache = unsafe { (*effect).get_cache() };
    let info = &mut cache.info;
    let (input_count, output_count) = (info.inputs as usize, info.outputs as usize);
    let mut buffer = unsafe {
        AudioBuffer::from_raw(
            input_count,
            output_count,
            raw_inputs,
            raw_outputs,
            samples as usize,
        )
    };
    plugin.process(&mut buffer);
}

/// VST2.4 replacing function with `f64` values.
pub fn process_replacing_f64(
    effect: *mut AEffect,
    raw_inputs: *const *const f64,
    raw_outputs: *mut *mut f64,
    samples: i32,
) {
    let plugin = unsafe { (*effect).get_plugin() };
    let cache = unsafe { (*effect).get_cache() };
    let info = &mut cache.info;
    let (input_count, output_count) = (info.inputs as usize, info.outputs as usize);
    let mut buffer = unsafe {
        AudioBuffer::from_raw(
            input_count,
            output_count,
            raw_inputs,
            raw_outputs,
            samples as usize,
        )
    };
    plugin.process_f64(&mut buffer);
}

/// VST2.4 set parameter function.
pub fn set_parameter(effect: *mut AEffect, index: i32, value: f32) {
    unsafe { (*effect).get_plugin() }.set_parameter(index, value);
}

/// VST2.4 get parameter function.
pub fn get_parameter(effect: *mut AEffect, index: i32) -> f32 {
    unsafe { (*effect).get_plugin() }.get_parameter(index)
}

/// Copy a string into a destination buffer.
///
/// String will be cut at `max` characters.
fn copy_string(dst: *mut c_void, src: &str, max: usize) -> isize {
    unsafe {
        use std::cmp::min;
        use libc::{c_void, memset, memcpy};

        let dst = dst as *mut c_void;
        memset(dst, 0, max);
        memcpy(dst, src.as_ptr() as *const c_void, min(max, src.as_bytes().len()));
    }

    1 // Success
}

/// VST2.4 dispatch function. This function handles dispatching all opcodes to the VST plugin.
pub fn dispatch(
    effect: *mut AEffect,
    opcode: i32,
    index: i32,
    value: isize,
    ptr: *mut c_void,
    opt: f32,
) -> isize {
    use plugin::{CanDo, OpCode};

    // Convert passed in opcode to enum
    let opcode = OpCode::from(opcode);
    // Plugin handle
    let plugin = unsafe { (*effect).get_plugin() };

    match opcode {
        OpCode::Initialize => plugin.init(),
        OpCode::Shutdown => unsafe {
            (*effect).drop_plugin();
            drop(mem::transmute::<*mut AEffect, Box<AEffect>>(effect));
        },

        OpCode::ChangePreset => plugin.change_preset(value as i32),
        OpCode::GetCurrentPresetNum => return plugin.get_preset_num() as isize,
        OpCode::SetCurrentPresetName => plugin.set_preset_name(read_string(ptr)),
        OpCode::GetCurrentPresetName => {
            let num = plugin.get_preset_num();
            return copy_string(ptr, &plugin.get_preset_name(num), MAX_PRESET_NAME_LEN);
        }

        OpCode::GetParameterLabel => {
            return copy_string(ptr, &plugin.get_parameter_label(index), MAX_PARAM_STR_LEN)
        }
        OpCode::GetParameterDisplay => {
            return copy_string(ptr, &plugin.get_parameter_text(index), MAX_PARAM_STR_LEN)
        }
        OpCode::GetParameterName => {
            return copy_string(ptr, &plugin.get_parameter_name(index), MAX_PARAM_STR_LEN)
        }

        OpCode::SetSampleRate => plugin.set_sample_rate(opt),
        OpCode::SetBlockSize => plugin.set_block_size(value as i64),
        OpCode::StateChanged => {
            if value == 1 {
                plugin.resume();
            } else {
                plugin.suspend();
            }
        }

        OpCode::EditorGetRect => {
            if let Some(editor) = plugin.get_editor() {
                let size = editor.size();
                let pos = editor.position();

                unsafe {
                    // Given a Rect** structure
                    // TODO: Investigate whether we are given a valid Rect** pointer already
                    *(ptr as *mut *mut c_void) = Box::into_raw(Box::new(Rect {
                        left: pos.0 as i16, // x coord of position
                        top: pos.1 as i16, // y coord of position
                        right: (pos.0 + size.0) as i16, // x coord of pos + x coord of size
                        bottom: (pos.1 + size.1) as i16, // y coord of pos + y coord of size
                    })) as *mut _; // TODO: free memory
                }
            }
        }
        OpCode::EditorOpen => {
            if let Some(editor) = plugin.get_editor() {
                editor.open(ptr); //ptr is raw window handle, eg HWND* on windows
            }
        }
        OpCode::EditorClose => {
            if let Some(editor) = plugin.get_editor() {
                editor.close();
            }
        }

        OpCode::EditorIdle => {
            if let Some(editor) = plugin.get_editor() {
                editor.idle();
            }
        }

        OpCode::GetData => {
            let mut chunks = if index == 0 {
                plugin.get_bank_data()
            } else {
                plugin.get_preset_data()
            };

            chunks.shrink_to_fit();
            let len = chunks.len() as isize; // eventually we should be using ffi::size_t

            unsafe {
                *(ptr as *mut *mut c_void) = chunks.as_ptr() as *mut c_void;
            }

            mem::forget(chunks);
            return len;
        }
        OpCode::SetData => {
            let chunks = unsafe { slice::from_raw_parts(ptr as *mut u8, value as usize) };

            if index == 0 {
                plugin.load_bank_data(chunks);
            } else {
                plugin.load_preset_data(chunks);
            }
        }

        OpCode::ProcessEvents => {
            plugin.process_events(unsafe { &*(ptr as *const api::Events) });
        }
        OpCode::CanBeAutomated => return plugin.can_be_automated(index) as isize,
        OpCode::StringToParameter => {
            return plugin.string_to_parameter(index, read_string(ptr)) as isize
        }

        OpCode::GetPresetName => {
            return copy_string(ptr, &plugin.get_preset_name(index), MAX_PRESET_NAME_LEN)
        }

        OpCode::GetInputInfo => {
            if index >= 0 && index < plugin.get_info().inputs {
                unsafe {
                    let ptr = ptr as *mut api::ChannelProperties;
                    *ptr = plugin.get_input_info(index).into();
                }
            }
        }
        OpCode::GetOutputInfo => {
            if index >= 0 && index < plugin.get_info().outputs {
                unsafe {
                    let ptr = ptr as *mut api::ChannelProperties;
                    *ptr = plugin.get_output_info(index).into();
                }
            }
        }
        OpCode::GetCategory => {
            return plugin.get_info().category.into();
        }

        OpCode::GetVendorName => {
            return copy_string(ptr, &plugin.get_info().vendor, MAX_VENDOR_STR_LEN)
        }
        OpCode::GetProductName => {
            return copy_string(ptr, &plugin.get_info().name, MAX_PRODUCT_STR_LEN)
        }
        OpCode::GetVendorVersion => return plugin.get_info().version as isize,
        OpCode::VendorSpecific => return plugin.vendor_specific(index, value, ptr, opt),
        OpCode::CanDo => {
            let can_do = CanDo::from_str(&read_string(ptr));
            return plugin.can_do(can_do).into();
        }
        OpCode::GetTailSize => {
            if plugin.get_tail_size() == 0 {
                return 1;
            } else {
                return plugin.get_tail_size();
            }
        }

        //OpCode::GetParamInfo => { /*TODO*/ }
        OpCode::GetApiVersion => return 2400,

        OpCode::EditorKeyDown => {
            if let Some(editor) = plugin.get_editor() {
                editor.key_down(KeyCode {
                    character: index as u8 as char,
                    key: Key::from(value),
                    modifier: unsafe { mem::transmute::<f32, i32>(opt) } as u8,
                });
            }
        }
        OpCode::EditorKeyUp => {
            if let Some(editor) = plugin.get_editor() {
                editor.key_up(KeyCode {
                    character: index as u8 as char,
                    key: Key::from(value),
                    modifier: unsafe { mem::transmute::<f32, i32>(opt) } as u8,
                });
            }
        }
        OpCode::EditorSetKnobMode => {
            if let Some(editor) = plugin.get_editor() {
                editor.set_knob_mode(KnobMode::from(value));
            }
        }

        OpCode::StartProcess => plugin.start_process(),
        OpCode::StopProcess => plugin.stop_process(),

        OpCode::GetNumMidiInputs => {
            return unsafe { (*effect).get_cache() }.info.midi_inputs as isize
        }
        OpCode::GetNumMidiOutputs => {
            return unsafe { (*effect).get_cache() }.info.midi_outputs as isize
        }

        _ => {
            debug!("Unimplemented opcode ({:?})", opcode);
            trace!(
                "Arguments; index: {}, value: {}, ptr: {:?}, opt: {}",
                index,
                value,
                ptr,
                opt
            );
        }
    }

    0
}

pub fn host_dispatch(
    host: &mut Host,
    effect: *mut AEffect,
    opcode: i32,
    index: i32,
    value: isize,
    ptr: *mut c_void,
    opt: f32,
) -> isize {
    use host::OpCode;

    match OpCode::from(opcode) {
        OpCode::Version => return 2400,
        OpCode::Automate => host.automate(index, opt),

        OpCode::Idle => host.idle(),

        // ...
        OpCode::CanDo => {
            info!("Plugin is asking if host can: {}.", read_string(ptr));
        }

        OpCode::GetVendorVersion => return host.get_info().0,
        OpCode::GetVendorString => return copy_string(ptr, &host.get_info().1, MAX_VENDOR_STR_LEN),
        OpCode::GetProductString => {
            return copy_string(ptr, &host.get_info().2, MAX_PRODUCT_STR_LEN)
        }
        OpCode::ProcessEvents => {
            host.process_events(unsafe { &*(ptr as *const api::Events) });
        }

        OpCode::GetTime => {
            return match host.get_time_info(value as i32) {
                None => 0,
                Some(result) => {
                    thread_local! {
                        static TIME_INFO: Cell<TimeInfo> =
                            Cell::new(TimeInfo::default());
                    }
                    TIME_INFO.with(|time_info| {
                        (*time_info).set(result);
                        time_info.as_ptr() as isize
                    })
                }
            };
        }
        OpCode::GetBlockSize => return host.get_block_size(),

        unimplemented => {
            trace!("VST: Got unimplemented host opcode ({:?})", unimplemented);
            trace!(
                "Arguments; effect: {:?}, index: {}, value: {}, ptr: {:?}, opt: {}",
                effect,
                index,
                value,
                ptr,
                opt
            );
        }
    }
    0
}

// Read a string from the `ptr` buffer
fn read_string(ptr: *mut c_void) -> String {
    use std::ffi::CStr;

    String::from_utf8_lossy(unsafe { CStr::from_ptr(ptr as *mut c_char).to_bytes() }).into_owned()
}
<commit_msg>OpCode::EditorOpen: return 1 if editor opened successfully<commit_after>//! Function interfaces for VST 2.4 API.

#![doc(hidden)]

use std::{mem, slice};
use std::cell::Cell;
use std::os::raw::{c_char, c_void};

use buffer::AudioBuffer;
use api::consts::*;
use api::{self, AEffect, TimeInfo};
use editor::{Key, KeyCode, KnobMode, Rect};
use host::Host;

/// Deprecated process function.
pub fn process_deprecated(
    _effect: *mut AEffect,
    _raw_inputs: *const *const f32,
    _raw_outputs: *mut *mut f32,
    _samples: i32,
) {
}

/// VST2.4 replacing function.
pub fn process_replacing(
    effect: *mut AEffect,
    raw_inputs: *const *const f32,
    raw_outputs: *mut *mut f32,
    samples: i32,
) {
    // Handle to the VST
    let plugin = unsafe { (*effect).get_plugin() };
    let cache = unsafe { (*effect).get_cache() };
    let info = &mut cache.info;
    let (input_count, output_count) = (info.inputs as usize, info.outputs as usize);
    let mut buffer = unsafe {
        AudioBuffer::from_raw(
            input_count,
            output_count,
            raw_inputs,
            raw_outputs,
            samples as usize,
        )
    };
    plugin.process(&mut buffer);
}

/// VST2.4 replacing function with `f64` values.
pub fn process_replacing_f64(
    effect: *mut AEffect,
    raw_inputs: *const *const f64,
    raw_outputs: *mut *mut f64,
    samples: i32,
) {
    let plugin = unsafe { (*effect).get_plugin() };
    let cache = unsafe { (*effect).get_cache() };
    let info = &mut cache.info;
    let (input_count, output_count) = (info.inputs as usize, info.outputs as usize);
    let mut buffer = unsafe {
        AudioBuffer::from_raw(
            input_count,
            output_count,
            raw_inputs,
            raw_outputs,
            samples as usize,
        )
    };
    plugin.process_f64(&mut buffer);
}

/// VST2.4 set parameter function.
pub fn set_parameter(effect: *mut AEffect, index: i32, value: f32) {
    unsafe { (*effect).get_plugin() }.set_parameter(index, value);
}

/// VST2.4 get parameter function.
pub fn get_parameter(effect: *mut AEffect, index: i32) -> f32 {
    unsafe { (*effect).get_plugin() }.get_parameter(index)
}

/// Copy a string into a destination buffer.
///
/// String will be cut at `max` characters.
fn copy_string(dst: *mut c_void, src: &str, max: usize) -> isize {
    unsafe {
        use std::cmp::min;
        use libc::{c_void, memset, memcpy};

        let dst = dst as *mut c_void;
        memset(dst, 0, max);
        memcpy(dst, src.as_ptr() as *const c_void, min(max, src.as_bytes().len()));
    }

    1 // Success
}

/// VST2.4 dispatch function. This function handles dispatching all opcodes to the VST plugin.
pub fn dispatch(
    effect: *mut AEffect,
    opcode: i32,
    index: i32,
    value: isize,
    ptr: *mut c_void,
    opt: f32,
) -> isize {
    use plugin::{CanDo, OpCode};

    // Convert passed in opcode to enum
    let opcode = OpCode::from(opcode);
    // Plugin handle
    let plugin = unsafe { (*effect).get_plugin() };

    match opcode {
        OpCode::Initialize => plugin.init(),
        OpCode::Shutdown => unsafe {
            (*effect).drop_plugin();
            drop(mem::transmute::<*mut AEffect, Box<AEffect>>(effect));
        },

        OpCode::ChangePreset => plugin.change_preset(value as i32),
        OpCode::GetCurrentPresetNum => return plugin.get_preset_num() as isize,
        OpCode::SetCurrentPresetName => plugin.set_preset_name(read_string(ptr)),
        OpCode::GetCurrentPresetName => {
            let num = plugin.get_preset_num();
            return copy_string(ptr, &plugin.get_preset_name(num), MAX_PRESET_NAME_LEN);
        }

        OpCode::GetParameterLabel => {
            return copy_string(ptr, &plugin.get_parameter_label(index), MAX_PARAM_STR_LEN)
        }
        OpCode::GetParameterDisplay => {
            return copy_string(ptr, &plugin.get_parameter_text(index), MAX_PARAM_STR_LEN)
        }
        OpCode::GetParameterName => {
            return copy_string(ptr, &plugin.get_parameter_name(index), MAX_PARAM_STR_LEN)
        }

        OpCode::SetSampleRate => plugin.set_sample_rate(opt),
        OpCode::SetBlockSize => plugin.set_block_size(value as i64),
        OpCode::StateChanged => {
            if value == 1 {
                plugin.resume();
            } else {
                plugin.suspend();
            }
        }

        OpCode::EditorGetRect => {
            if let Some(editor) = plugin.get_editor() {
                let size = editor.size();
                let pos = editor.position();

                unsafe {
                    // Given a Rect** structure
                    // TODO: Investigate whether we are given a valid Rect** pointer already
                    *(ptr as *mut *mut c_void) = Box::into_raw(Box::new(Rect {
                        left: pos.0 as i16, // x coord of position
                        top: pos.1 as i16, // y coord of position
                        right: (pos.0 + size.0) as i16, // x coord of pos + x coord of size
                        bottom: (pos.1 + size.1) as i16, // y coord of pos + y coord of size
                    })) as *mut _; // TODO: free memory
                }
            }
        }
        OpCode::EditorOpen => {
            if let Some(editor) = plugin.get_editor() {
                editor.open(ptr); //ptr is raw window handle, eg HWND* on windows
                return 1;
            }
        }
        OpCode::EditorClose => {
            if let Some(editor) = plugin.get_editor() {
                editor.close();
            }
        }

        OpCode::EditorIdle => {
            if let Some(editor) = plugin.get_editor() {
                editor.idle();
            }
        }

        OpCode::GetData => {
            let mut chunks = if index == 0 {
                plugin.get_bank_data()
            } else {
                plugin.get_preset_data()
            };

            chunks.shrink_to_fit();
            let len = chunks.len() as isize; // eventually we should be using ffi::size_t

            unsafe {
                *(ptr as *mut *mut c_void) = chunks.as_ptr() as *mut c_void;
            }

            mem::forget(chunks);
            return len;
        }
        OpCode::SetData => {
            let chunks = unsafe { slice::from_raw_parts(ptr as *mut u8, value as usize) };

            if index == 0 {
                plugin.load_bank_data(chunks);
            } else {
                plugin.load_preset_data(chunks);
            }
        }

        OpCode::ProcessEvents => {
            plugin.process_events(unsafe { &*(ptr as *const api::Events) });
        }
        OpCode::CanBeAutomated => return plugin.can_be_automated(index) as isize,
        OpCode::StringToParameter => {
            return plugin.string_to_parameter(index, read_string(ptr)) as isize
        }

        OpCode::GetPresetName => {
            return copy_string(ptr, &plugin.get_preset_name(index), MAX_PRESET_NAME_LEN)
        }

        OpCode::GetInputInfo => {
            if index >= 0 && index < plugin.get_info().inputs {
                unsafe {
                    let ptr = ptr as *mut api::ChannelProperties;
                    *ptr = plugin.get_input_info(index).into();
                }
            }
        }
        OpCode::GetOutputInfo => {
            if index >= 0 && index < plugin.get_info().outputs {
                unsafe {
                    let ptr = ptr as *mut api::ChannelProperties;
                    *ptr = plugin.get_output_info(index).into();
                }
            }
        }
        OpCode::GetCategory => {
            return plugin.get_info().category.into();
        }

        OpCode::GetVendorName => {
            return copy_string(ptr, &plugin.get_info().vendor, MAX_VENDOR_STR_LEN)
        }
        OpCode::GetProductName => {
            return copy_string(ptr, &plugin.get_info().name, MAX_PRODUCT_STR_LEN)
        }
        OpCode::GetVendorVersion => return plugin.get_info().version as isize,
        OpCode::VendorSpecific => return plugin.vendor_specific(index, value, ptr, opt),
        OpCode::CanDo => {
            let can_do = CanDo::from_str(&read_string(ptr));
            return plugin.can_do(can_do).into();
        }
        OpCode::GetTailSize => {
            if plugin.get_tail_size() == 0 {
                return 1;
            } else {
                return plugin.get_tail_size();
            }
        }

        //OpCode::GetParamInfo => { /*TODO*/ }
        OpCode::GetApiVersion => return 2400,

        OpCode::EditorKeyDown => {
            if let Some(editor) = plugin.get_editor() {
                editor.key_down(KeyCode {
                    character: index as u8 as char,
                    key: Key::from(value),
                    modifier: unsafe { mem::transmute::<f32, i32>(opt) } as u8,
                });
            }
        }
        OpCode::EditorKeyUp => {
            if let Some(editor) = plugin.get_editor() {
                editor.key_up(KeyCode {
                    character: index as u8 as char,
                    key: Key::from(value),
                    modifier: unsafe { mem::transmute::<f32, i32>(opt) } as u8,
                });
            }
        }
        OpCode::EditorSetKnobMode => {
            if let Some(editor) = plugin.get_editor() {
                editor.set_knob_mode(KnobMode::from(value));
            }
        }

        OpCode::StartProcess => plugin.start_process(),
        OpCode::StopProcess => plugin.stop_process(),

        OpCode::GetNumMidiInputs => {
            return unsafe { (*effect).get_cache() }.info.midi_inputs as isize
        }
        OpCode::GetNumMidiOutputs => {
            return unsafe { (*effect).get_cache() }.info.midi_outputs as isize
        }

        _ => {
            debug!("Unimplemented opcode ({:?})", opcode);
            trace!(
                "Arguments; index: {}, value: {}, ptr: {:?}, opt: {}",
                index,
                value,
                ptr,
                opt
            );
        }
    }

    0
}

pub fn host_dispatch(
    host: &mut Host,
    effect: *mut AEffect,
    opcode: i32,
    index: i32,
    value: isize,
    ptr: *mut c_void,
    opt: f32,
) -> isize {
    use host::OpCode;

    match OpCode::from(opcode) {
        OpCode::Version => return 2400,
        OpCode::Automate => host.automate(index, opt),

        OpCode::Idle => host.idle(),

        // ...
        OpCode::CanDo => {
            info!("Plugin is asking if host can: {}.", read_string(ptr));
        }

        OpCode::GetVendorVersion => return host.get_info().0,
        OpCode::GetVendorString => return copy_string(ptr, &host.get_info().1, MAX_VENDOR_STR_LEN),
        OpCode::GetProductString => {
            return copy_string(ptr, &host.get_info().2, MAX_PRODUCT_STR_LEN)
        }
        OpCode::ProcessEvents => {
            host.process_events(unsafe { &*(ptr as *const api::Events) });
        }

        OpCode::GetTime => {
            return match host.get_time_info(value as i32) {
                None => 0,
                Some(result) => {
                    thread_local! {
                        static TIME_INFO: Cell<TimeInfo> =
                            Cell::new(TimeInfo::default());
                    }
                    TIME_INFO.with(|time_info| {
                        (*time_info).set(result);
                        time_info.as_ptr() as isize
                    })
                }
            };
        }
        OpCode::GetBlockSize => return host.get_block_size(),

        unimplemented => {
            trace!("VST: Got unimplemented host opcode ({:?})", unimplemented);
            trace!(
                "Arguments; effect: {:?}, index: {}, value: {}, ptr: {:?}, opt: {}",
                effect,
                index,
                value,
                ptr,
                opt
            );
        }
    }
    0
}

// Read a string from the `ptr` buffer
fn read_string(ptr: *mut c_void) -> String {
    use std::ffi::CStr;

    String::from_utf8_lossy(unsafe { CStr::from_ptr(ptr as *mut c_char).to_bytes() }).into_owned()
}
<|endoftext|>


<commit_before>use std::io::{self, Write};
use termion::event::Key;
use Editor;
use event::*;

pub trait KeyMap<'a, W: Write, T>: From<T> {
    fn handle_key_core(&mut self, key: Key) -> io::Result<()>;
    fn editor(&mut self) -> &mut Editor<'a, W>;

    fn handle_key(&mut self, key: Key, handler: &mut EventHandler<W>) -> io::Result<bool> {
        let mut done = false;

        handler(Event::new(self.editor(), EventKind::BeforeKey(key)));

        match key {
            Key::Char('\t') => try!(self.editor().complete(handler)),
            Key::Char('\n') => {
                try!(self.editor().handle_newline());
                done = true;
            }
            Key::Ctrl('f') => {
                try!(self.editor().accept_autosuggestion());
            }
            _ => {
                try!(self.handle_key_core(key));
                self.editor().skip_completions_hint();
            }
        };

        handler(Event::new(self.editor(), EventKind::AfterKey(key)));

        try!(self.editor().flush());

        Ok(done)
    }
}

pub mod vi;
pub use vi::Vi;

pub mod emacs;
pub use emacs::Emacs;
<commit_msg>notify the caller of ctrl-c presses<commit_after>use std::io::{self, Write, ErrorKind};
use termion::event::Key;
use Editor;
use event::*;

pub trait KeyMap<'a, W: Write, T>: From<T> {
    fn handle_key_core(&mut self, key: Key) -> io::Result<()>;
    fn editor(&mut self) -> &mut Editor<'a, W>;

    fn handle_key(&mut self, key: Key, handler: &mut EventHandler<W>) -> io::Result<bool> {
        let mut done = false;

        handler(Event::new(self.editor(), EventKind::BeforeKey(key)));

        match key {
            Key::Ctrl('c') => {
                try!(self.editor().handle_newline());
                return Err(io::Error::new(ErrorKind::Interrupted, "ctrl-c"));
            }
            Key::Char('\t') => try!(self.editor().complete(handler)),
            Key::Char('\n') => {
                try!(self.editor().handle_newline());
                done = true;
            }
            Key::Ctrl('f') => {
                try!(self.editor().accept_autosuggestion());
            }
            _ => {
                try!(self.handle_key_core(key));
                self.editor().skip_completions_hint();
            }
        };

        handler(Event::new(self.editor(), EventKind::AfterKey(key)));

        try!(self.editor().flush());

        Ok(done)
    }
}

pub mod vi;
pub use vi::Vi;

pub mod emacs;
pub use emacs::Emacs;

#[cfg(test)]
mod tests {
    use super::*;
    use termion::event::Key::*;
    use std::io::ErrorKind;
    use Context;

    struct TestKeyMap<'a, W: Write> {
        ed: Editor<'a, W>,
    }

    impl<'a, W: Write> TestKeyMap<'a, W> {
        pub fn new(ed: Editor<'a, W>) -> Self {
            TestKeyMap {
                ed: ed,
            }
        }
    }

    impl<'a, W: Write> KeyMap<'a, W, TestKeyMap<'a, W>> for TestKeyMap<'a, W> {
        fn handle_key_core(&mut self, _: Key) -> io::Result<()> {
            Ok(())
        }

        fn editor(&mut self) ->  &mut Editor<'a, W> {
            &mut self.ed
        }
    }

    #[test]
    /// ctrl-c should generate an error
    fn ctrl_c() {
        let mut context = Context::new();
        let out = Vec::new();
        let ed = Editor::new(out, "prompt".to_owned(), &mut context).unwrap();
        let mut map = TestKeyMap::new(ed);

        let res = map.handle_key(Ctrl('c'), &mut |_| {});
        assert_eq!(res.is_err(), true);
        assert_eq!(res.err().unwrap().kind(), ErrorKind::Interrupted);
    }
}
<|endoftext|>


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    fn get_shell_list() {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    fn get_shell_list() {

    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(generators)]

fn foo(_b: &bool, _a: ()) {}

fn main() {
	|| {
		let b = true;
		foo(&b, yield); // ERROR `b` does not live long enough
	};
}
<commit_msg>Convert tabs to spaces<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(generators)]

fn foo(_b: &bool, _a: ()) {}

fn main() {
    || {
        let b = true;
        foo(&b, yield); // ERROR `b` does not live long enough
    };
}
<|endoftext|>


<commit_before>/// low level wrapper for the state machine, encoding and decoding from lapin-async
use lapin_async::connection::*;
use lapin_async::format::frame::*;

use nom::{IResult,Offset};
use cookie_factory::GenError;
use bytes::BytesMut;
use std::iter::repeat;
use std::io::{self,Error,ErrorKind};
use std::time::Duration;
use futures::{Async,Poll,Sink,Stream,StartSend,Future};
use tokio_io::{AsyncRead,AsyncWrite};
use tokio_io::codec::{Decoder,Encoder,Framed};
use tokio_timer::{Interval,Timer};
use client::ConnectionOptions;

/// implements tokio-io's Decoder and Encoder
pub struct AMQPCodec;

impl Decoder for AMQPCodec {
    type Item = Frame;
    type Error = io::Error;

    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Frame>, io::Error> {
        let (consumed, f) = match frame(buf) {
          IResult::Incomplete(_) => {
            return Ok(None)
          },
          IResult::Error(e) => {
            return Err(io::Error::new(io::ErrorKind::Other, format!("parse error: {:?}", e)))
          },
          IResult::Done(i, frame) => {
            (buf.offset(i), frame)
          }
        };

        trace!("decoded frame: {:?}", f);

        buf.split_to(consumed);

        Ok(Some(f))
    }
}

impl Encoder for AMQPCodec {
    type Item = Frame;
    type Error = io::Error;

    fn encode(&mut self, frame: Frame, buf: &mut BytesMut) -> Result<(), Self::Error> {
      let length = buf.len();
      if length < 8192 {
        //reserve more capacity and intialize it
        buf.extend(repeat(0).take(8192 - length));
      }
      trace!("will encode and write frame: {:?}", frame);

      loop {
        let gen_res = match &frame {
          &Frame::ProtocolHeader => {
            gen_protocol_header((buf, 0)).map(|tup| tup.1)
          },
          &Frame::Heartbeat(_) => {
            gen_heartbeat_frame((buf, 0)).map(|tup| tup.1)
          },
          &Frame::Method(channel, ref method) => {
            gen_method_frame((buf, 0), channel, method).map(|tup| tup.1)
          },
          &Frame::Header(channel_id, class_id, ref header) => {
            gen_content_header_frame((buf, 0), channel_id, class_id, header.body_size, &header.properties).map(|tup| tup.1)
          },
          &Frame::Body(channel_id, ref data) => {
            gen_content_body_frame((buf, 0), channel_id, data).map(|tup| tup.1)
          }
        };

        match gen_res {
          Ok(sz) => {
            buf.truncate(sz);
            trace!("serialized frame: {} bytes", sz);
            return Ok(());
          },
          Err(e) => {
            error!("error generating frame: {:?}", e);
            match e {
              GenError::BufferTooSmall(sz) => {
                buf.extend(repeat(0).take(sz - length));
                //return Err(Error::new(ErrorKind::InvalidData, "send buffer too small"));
              },
              GenError::InvalidOffset | GenError::CustomError(_) | GenError::NotYetImplemented => {
                return Err(Error::new(ErrorKind::InvalidData, "could not generate"));
              }
            }
          }
        }
      }
    }
}

/// Wrappers over a `Framed` stream using `AMQPCodec` and lapin-async's `Connection`
pub struct AMQPTransport<T> {
  upstream: Framed<T,AMQPCodec>,
  heartbeat: Interval,
  pub conn: Connection,
}

impl<T> AMQPTransport<T>
   where T: AsyncRead+AsyncWrite,
         T: 'static               {

  /// starts the connection process
  ///
  /// returns a future of a `AMQPTransport` that is connected
  pub fn connect(upstream: Framed<T,AMQPCodec>, options: &ConnectionOptions) -> Box<Future<Item = AMQPTransport<T>, Error = io::Error>> {
    let mut conn = Connection::new();
    conn.set_credentials(&options.username, &options.password);
    conn.set_vhost(&options.vhost);
    conn.set_heartbeat(options.heartbeat);
    conn.connect();

    let mut t = AMQPTransport {
      upstream:  upstream,
      heartbeat: Timer::default().interval(Duration::from_secs(conn.configuration.heartbeat as u64)),
      conn:      conn,
    };

    t.send_and_handle_frames();
    t.poll();

    let mut connector = AMQPTransportConnector {
      transport: Some(t)
    };

    trace!("pre-poll");
    connector.poll();
    trace!("post-poll");

    Box::new(connector)
  }

  fn poll_heartbeat(&mut self) {
    if let Ok(Async::Ready(_)) = self.heartbeat.poll() {
      debug!("Heartbeat");
      self.start_send(Frame::Heartbeat(0));
      self.poll_complete();
    }
  }

  fn poll_upstream(&mut self) -> Poll<Option<()>, io::Error> {
    let value = match self.upstream.poll() {
      Ok(Async::Ready(t)) => t,
      Ok(Async::NotReady) => {
        trace!("upstream poll gave NotReady");
        return Ok(Async::NotReady);
      },
      Err(e) => {
        error!("upstream poll gave error: {:?}", e);
        return Err(From::from(e));
      },
    };

    if let Some(frame) = value {
      trace!("upstream poll gave frame: {:?}", frame);
      self.conn.handle_frame(frame);
      self.send_frames();
      self.upstream.poll_complete();
      Ok(Async::Ready(Some(())))
    } else {
      error!("upstream poll gave Ready(None)");
      Ok(Async::Ready(None))
    }
  }

  pub fn send_and_handle_frames(&mut self) {
    self.send_frames();
    self.handle_frames();
  }

  pub fn send_frames(&mut self) {
    //FIXME: find a way to use a future here
    while let Some(f) = self.conn.next_frame() {
      self.upstream.start_send(f);
      self.upstream.poll_complete();
    }
    //self.upstream.poll_complete();
  }

  pub fn handle_frames(&mut self) {
    while let Ok(Async::Ready(Some(_))) = self.poll() {}
  }
}

/// implements a future of `AMQPTransport`
///
/// this structure is used to perform the AMQP handshake and provide
/// a connected transport afterwards
pub struct AMQPTransportConnector<T> {
  pub transport: Option<AMQPTransport<T>>,
}

impl<T> Future for AMQPTransportConnector<T>
    where T: AsyncRead + AsyncWrite,
          T: 'static {

  type Item  = AMQPTransport<T>;
  type Error = io::Error;

  fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
    debug!("AMQPTransportConnector poll transport is none? {}", self.transport.is_none());
    let mut transport = self.transport.take().unwrap();

    //we might have received a frame before here
    transport.send_and_handle_frames();

    debug!("conn state: {:?}", transport.conn.state);
    if transport.conn.state == ConnectionState::Connected {
      debug!("already connected");
      return Ok(Async::Ready(transport))
    }

    trace!("waiting before poll");
    transport.poll().map(|value| {
      match value {
        Async::Ready(Some(_)) => {
          if transport.conn.state == ConnectionState::Connected {
            // Upstream had frames available and we're connected, the transport is ready
            Async::Ready(transport)
          } else {
            // Upstream had frames but we're not yet connected, continue polling
            transport.poll();
            self.transport = Some(transport);
            Async::NotReady
          }
        },
        _ => {
          // Upstream had no frames
          self.transport = Some(transport);
          Async::NotReady
        },
      }
    })
  }
}

impl<T> Stream for AMQPTransport<T>
    where T: AsyncRead + AsyncWrite,
          T: 'static {
    type Item = ();
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<()>, io::Error> {
      trace!("stream poll");
      self.poll_heartbeat();
      self.poll_upstream()
    }
}

impl<T> Sink for AMQPTransport<T>
    where T: AsyncWrite {
    type SinkItem = Frame;
    type SinkError = io::Error;

    fn start_send(&mut self, item: Frame) -> StartSend<Frame, io::Error> {
        trace!("sink start send");
        self.upstream.start_send(item)
    }

    fn poll_complete(&mut self) -> Poll<(), io::Error> {
        trace!("sink poll_complete");
        self.upstream.poll_complete()
    }
}

<commit_msg>futures: don't use upstream.poll_complete() directly<commit_after>/// low level wrapper for the state machine, encoding and decoding from lapin-async
use lapin_async::connection::*;
use lapin_async::format::frame::*;

use nom::{IResult,Offset};
use cookie_factory::GenError;
use bytes::BytesMut;
use std::iter::repeat;
use std::io::{self,Error,ErrorKind};
use std::time::Duration;
use futures::{Async,Poll,Sink,Stream,StartSend,Future};
use tokio_io::{AsyncRead,AsyncWrite};
use tokio_io::codec::{Decoder,Encoder,Framed};
use tokio_timer::{Interval,Timer};
use client::ConnectionOptions;

/// implements tokio-io's Decoder and Encoder
pub struct AMQPCodec;

impl Decoder for AMQPCodec {
    type Item = Frame;
    type Error = io::Error;

    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Frame>, io::Error> {
        let (consumed, f) = match frame(buf) {
          IResult::Incomplete(_) => {
            return Ok(None)
          },
          IResult::Error(e) => {
            return Err(io::Error::new(io::ErrorKind::Other, format!("parse error: {:?}", e)))
          },
          IResult::Done(i, frame) => {
            (buf.offset(i), frame)
          }
        };

        trace!("decoded frame: {:?}", f);

        buf.split_to(consumed);

        Ok(Some(f))
    }
}

impl Encoder for AMQPCodec {
    type Item = Frame;
    type Error = io::Error;

    fn encode(&mut self, frame: Frame, buf: &mut BytesMut) -> Result<(), Self::Error> {
      let length = buf.len();
      if length < 8192 {
        //reserve more capacity and intialize it
        buf.extend(repeat(0).take(8192 - length));
      }
      trace!("will encode and write frame: {:?}", frame);

      loop {
        let gen_res = match &frame {
          &Frame::ProtocolHeader => {
            gen_protocol_header((buf, 0)).map(|tup| tup.1)
          },
          &Frame::Heartbeat(_) => {
            gen_heartbeat_frame((buf, 0)).map(|tup| tup.1)
          },
          &Frame::Method(channel, ref method) => {
            gen_method_frame((buf, 0), channel, method).map(|tup| tup.1)
          },
          &Frame::Header(channel_id, class_id, ref header) => {
            gen_content_header_frame((buf, 0), channel_id, class_id, header.body_size, &header.properties).map(|tup| tup.1)
          },
          &Frame::Body(channel_id, ref data) => {
            gen_content_body_frame((buf, 0), channel_id, data).map(|tup| tup.1)
          }
        };

        match gen_res {
          Ok(sz) => {
            buf.truncate(sz);
            trace!("serialized frame: {} bytes", sz);
            return Ok(());
          },
          Err(e) => {
            error!("error generating frame: {:?}", e);
            match e {
              GenError::BufferTooSmall(sz) => {
                buf.extend(repeat(0).take(sz - length));
                //return Err(Error::new(ErrorKind::InvalidData, "send buffer too small"));
              },
              GenError::InvalidOffset | GenError::CustomError(_) | GenError::NotYetImplemented => {
                return Err(Error::new(ErrorKind::InvalidData, "could not generate"));
              }
            }
          }
        }
      }
    }
}

/// Wrappers over a `Framed` stream using `AMQPCodec` and lapin-async's `Connection`
pub struct AMQPTransport<T> {
  upstream: Framed<T,AMQPCodec>,
  heartbeat: Interval,
  pub conn: Connection,
}

impl<T> AMQPTransport<T>
   where T: AsyncRead+AsyncWrite,
         T: 'static               {

  /// starts the connection process
  ///
  /// returns a future of a `AMQPTransport` that is connected
  pub fn connect(upstream: Framed<T,AMQPCodec>, options: &ConnectionOptions) -> Box<Future<Item = AMQPTransport<T>, Error = io::Error>> {
    let mut conn = Connection::new();
    conn.set_credentials(&options.username, &options.password);
    conn.set_vhost(&options.vhost);
    conn.set_heartbeat(options.heartbeat);
    conn.connect();

    let mut t = AMQPTransport {
      upstream:  upstream,
      heartbeat: Timer::default().interval(Duration::from_secs(conn.configuration.heartbeat as u64)),
      conn:      conn,
    };

    t.send_and_handle_frames();
    t.poll();

    let mut connector = AMQPTransportConnector {
      transport: Some(t)
    };

    trace!("pre-poll");
    connector.poll();
    trace!("post-poll");

    Box::new(connector)
  }

  fn poll_heartbeat(&mut self) {
    if let Ok(Async::Ready(_)) = self.heartbeat.poll() {
      debug!("Heartbeat");
      self.start_send(Frame::Heartbeat(0));
      self.poll_complete();
    }
  }

  fn poll_upstream(&mut self) -> Poll<Option<()>, io::Error> {
    let value = match self.upstream.poll() {
      Ok(Async::Ready(t)) => t,
      Ok(Async::NotReady) => {
        trace!("upstream poll gave NotReady");
        return Ok(Async::NotReady);
      },
      Err(e) => {
        error!("upstream poll gave error: {:?}", e);
        return Err(From::from(e));
      },
    };

    if let Some(frame) = value {
      trace!("upstream poll gave frame: {:?}", frame);
      self.conn.handle_frame(frame);
      self.send_frames();
      self.poll_complete();
      Ok(Async::Ready(Some(())))
    } else {
      error!("upstream poll gave Ready(None)");
      Ok(Async::Ready(None))
    }
  }

  pub fn send_and_handle_frames(&mut self) {
    self.send_frames();
    self.handle_frames();
  }

  pub fn send_frames(&mut self) {
    //FIXME: find a way to use a future here
    while let Some(f) = self.conn.next_frame() {
      self.upstream.start_send(f);
      self.poll_complete();
    }
    //self.poll_complete();
  }

  pub fn handle_frames(&mut self) {
    while let Ok(Async::Ready(Some(_))) = self.poll() {}
  }
}

/// implements a future of `AMQPTransport`
///
/// this structure is used to perform the AMQP handshake and provide
/// a connected transport afterwards
pub struct AMQPTransportConnector<T> {
  pub transport: Option<AMQPTransport<T>>,
}

impl<T> Future for AMQPTransportConnector<T>
    where T: AsyncRead + AsyncWrite,
          T: 'static {

  type Item  = AMQPTransport<T>;
  type Error = io::Error;

  fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
    debug!("AMQPTransportConnector poll transport is none? {}", self.transport.is_none());
    let mut transport = self.transport.take().unwrap();

    //we might have received a frame before here
    transport.send_and_handle_frames();

    debug!("conn state: {:?}", transport.conn.state);
    if transport.conn.state == ConnectionState::Connected {
      debug!("already connected");
      return Ok(Async::Ready(transport))
    }

    trace!("waiting before poll");
    transport.poll().map(|value| {
      match value {
        Async::Ready(Some(_)) => {
          if transport.conn.state == ConnectionState::Connected {
            // Upstream had frames available and we're connected, the transport is ready
            Async::Ready(transport)
          } else {
            // Upstream had frames but we're not yet connected, continue polling
            transport.poll();
            self.transport = Some(transport);
            Async::NotReady
          }
        },
        _ => {
          // Upstream had no frames
          self.transport = Some(transport);
          Async::NotReady
        },
      }
    })
  }
}

impl<T> Stream for AMQPTransport<T>
    where T: AsyncRead + AsyncWrite,
          T: 'static {
    type Item = ();
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<()>, io::Error> {
      trace!("stream poll");
      self.poll_heartbeat();
      self.poll_upstream()
    }
}

impl<T> Sink for AMQPTransport<T>
    where T: AsyncWrite {
    type SinkItem = Frame;
    type SinkError = io::Error;

    fn start_send(&mut self, item: Frame) -> StartSend<Frame, io::Error> {
        trace!("sink start send");
        self.upstream.start_send(item)
    }

    fn poll_complete(&mut self) -> Poll<(), io::Error> {
        trace!("sink poll_complete");
        self.upstream.poll_complete()
    }
}

<|endoftext|>


<commit_before>use core::pin::Pin;
use futures_core::future::TryFuture;
use futures_core::task::{Context, Poll};

#[must_use = "futures do nothing unless you `.await` or poll them"]
#[derive(Debug)]
pub(crate) enum TryChain<Fut1, Fut2, Data> {
    First(Fut1, Option<Data>),
    Second(Fut2),
    Empty,
}

pub(crate) enum TryChainAction<Fut2>
    where Fut2: TryFuture,
{
    Future(Fut2),
    Output(Result<Fut2::Ok, Fut2::Error>),
}

impl<Fut1, Fut2, Data> TryChain<Fut1, Fut2, Data>
    where Fut1: TryFuture,
          Fut2: TryFuture,
{
    pub(crate) fn new(fut1: Fut1, data: Data) -> TryChain<Fut1, Fut2, Data> {
        TryChain::First(fut1, Some(data))
    }

    pub(crate) fn is_terminated(&self) -> bool {
        match self {
            TryChain::First(..) | TryChain::Second(_) => true,
            TryChain::Empty => false,
        }
    }

    pub(crate) fn poll<F>(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        f: F,
    ) -> Poll<Result<Fut2::Ok, Fut2::Error>>
        where F: FnOnce(Result<Fut1::Ok, Fut1::Error>, Data) -> TryChainAction<Fut2>,
    {
        let mut f = Some(f);

        // Safe to call `get_unchecked_mut` because we won't move the futures.
        let this = unsafe { self.get_unchecked_mut() };

        loop {
            let (output, data) = match this {
                TryChain::First(fut1, data) => {
                    // Poll the first future
                    let output = ready!(unsafe { Pin::new_unchecked(fut1) }.try_poll(cx));
                    (output, data.take().unwrap())
                }
                TryChain::Second(fut2) => {
                    // Poll the second future
                    return unsafe { Pin::new_unchecked(fut2) }.try_poll(cx)
                }
                TryChain::Empty => {
                    panic!("future must not be polled after it returned `Poll::Ready`");
                }
            };

            *this = TryChain::Empty; // Drop fut1
            let f = f.take().unwrap();
            match f(output, data) {
                TryChainAction::Future(fut2) => *this = TryChain::Second(fut2),
                TryChainAction::Output(output) => return Poll::Ready(output),
            }
        }
    }
}
<commit_msg>Fix TryChain::is_terminated<commit_after>use core::pin::Pin;
use futures_core::future::TryFuture;
use futures_core::task::{Context, Poll};

#[must_use = "futures do nothing unless you `.await` or poll them"]
#[derive(Debug)]
pub(crate) enum TryChain<Fut1, Fut2, Data> {
    First(Fut1, Option<Data>),
    Second(Fut2),
    Empty,
}

pub(crate) enum TryChainAction<Fut2>
    where Fut2: TryFuture,
{
    Future(Fut2),
    Output(Result<Fut2::Ok, Fut2::Error>),
}

impl<Fut1, Fut2, Data> TryChain<Fut1, Fut2, Data>
    where Fut1: TryFuture,
          Fut2: TryFuture,
{
    pub(crate) fn new(fut1: Fut1, data: Data) -> TryChain<Fut1, Fut2, Data> {
        TryChain::First(fut1, Some(data))
    }

    pub(crate) fn is_terminated(&self) -> bool {
        match self {
            TryChain::First(..) | TryChain::Second(_) => false,
            TryChain::Empty => true,
        }
    }

    pub(crate) fn poll<F>(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        f: F,
    ) -> Poll<Result<Fut2::Ok, Fut2::Error>>
        where F: FnOnce(Result<Fut1::Ok, Fut1::Error>, Data) -> TryChainAction<Fut2>,
    {
        let mut f = Some(f);

        // Safe to call `get_unchecked_mut` because we won't move the futures.
        let this = unsafe { self.get_unchecked_mut() };

        loop {
            let (output, data) = match this {
                TryChain::First(fut1, data) => {
                    // Poll the first future
                    let output = ready!(unsafe { Pin::new_unchecked(fut1) }.try_poll(cx));
                    (output, data.take().unwrap())
                }
                TryChain::Second(fut2) => {
                    // Poll the second future
                    return unsafe { Pin::new_unchecked(fut2) }
                        .try_poll(cx)
                        .map(|res| {
                            *this = TryChain::Empty; // Drop fut2.
                            res
                        });
                }
                TryChain::Empty => {
                    panic!("future must not be polled after it returned `Poll::Ready`");
                }
            };

            *this = TryChain::Empty; // Drop fut1
            let f = f.take().unwrap();
            match f(output, data) {
                TryChainAction::Future(fut2) => *this = TryChain::Second(fut2),
                TryChainAction::Output(output) => return Poll::Ready(output),
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use std::pin::Pin;
    use std::task::Poll;

    use futures_test::task::noop_context;

    use crate::future::ready;

    use super::{TryChain, TryChainAction};

    #[test]
    fn try_chain_is_terminated() {
        let mut cx = noop_context();

        let mut future = TryChain::new(ready(Ok(1)), ());
        assert!(!future.is_terminated());

        let res = Pin::new(&mut future).poll(
            &mut cx,
            |res: Result<usize, ()>, ()| {
                assert!(res.is_ok());
                TryChainAction::Future(ready(Ok(2)))
            },
        );
        assert_eq!(res, Poll::Ready::<Result<usize, ()>>(Ok(2)));
        assert!(future.is_terminated());
    }
}
<|endoftext|>