<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2015 Johan Johansson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Token<'a> {
	LParen,
	RParen,
	LBracket,
	RBracket,
	LBrace,
	RBrace,
	Ident(&'a str),
	Number(&'a str),
	String(&'a str),
	Colon,
	Quote,
}

// TODO: Handle comments. Both on own lines, and at end of lines. Should probably be renamed aswell
// TODO: This whole function is very ugly. Separate string-related logic.
/// Split code string by whitespace. Preserve whitespace in string literals
pub fn split_by_whitespace(mut src: &str) -> Result<Vec<&str>, &'static str> {
	src = src.trim();

	let mut splits = Vec::with_capacity(src.len() / 2);

	let mut char_iter = src.char_indices();
	while let Some((byte_i, c)) = char_iter.next() {
		if c.is_whitespace() {
			continue;
		}

		let from_here = &src[byte_i..];

		// `Some` if item att current index is a string literal
		let maybe_start_len_and_delim = if let Some(0) = from_here.find('"') {
			// It's a string. Do not split by space in a string, instead send whole string literal
			// as a single token. Resume iterating from end of string.
			Some((1, String::from("\"")))
		} else if let Some(0) = from_here.find("r\"") {
			// Same as above, but raw string literal.
			Some((2, String::from("\"")))
		} else if let Some(0) = from_here.find("r#") {
			// Similar to above, but do not delimit by ", but rather "
			// followed by same number of #'s as preceeding beginning "
			from_here.find('"').and_then(|i| if from_here[1..i].bytes().all(|c| c == '#' as u8) {
				let s = String::from("\"") + &from_here[1..i];
				Some((s.len() + 1, s))
			} else {
				None
			})
		} else if from_here.starts_with(';') {
			// Comment. We know from above that we are not in a string, so just skip rest of line
			let comment_len = from_here.find('\n').map(|i| i + 1).unwrap_or(from_here.len());
			src = &src[byte_i + comment_len ..];
			char_iter = src.char_indices();
			continue;
		} else {
			None
		};

		if let Some((start_len, str_delim)) = maybe_start_len_and_delim {
			// It's a string literal
			if let Some(end_i) = from_here[start_len..]
				.find(&str_delim)
				.map(|i| i + start_len + str_delim.len())
			{
				splits.push(&from_here[..end_i]);

				src = &src[byte_i + end_i ..];
				char_iter = src.char_indices();
			} else {
				return Err("Undelimited string literal")
			}
		} else {
			// Not a string, just split until next space
			let end_i = from_here.find(|c: char| c.is_whitespace()).unwrap_or(from_here.len());
			splits.push(&from_here[..end_i]);

			src = &src[byte_i + end_i ..];
			char_iter = src.char_indices();
		}
	}

	Ok(splits)
}

fn is_ident_char(c: char) -> bool {
	match c {
		// TODO: Instead of allowing certain chars, just allow all non-reserved chars
		'_' | '?' | '/' | '+' | '-' | '*' | '=' | '&' | '→' | '>' | '<' | '\\' | '.' => true,
		c if c.is_alphanumeric() => true,
		_ => false,
	}
}

/// Tokenize a whitespace-less string of code (except in string literals)
pub fn tokenize_word(mut word: &str) -> Result<Vec<Token>, String> {
	if word.starts_with('"') || word.starts_with(r#"r""#) || word.starts_with("r#") {
		// The word is a string
		return Ok(vec![Token::String(word)]);
	}

	let mut tokens = Vec::with_capacity((word.len() * 3) / 2);

	while let Some(c) = word.chars().next() {
		let shift = match c {
			'(' => { tokens.push(Token::LParen); 1 },
			')' => { tokens.push(Token::RParen); 1 },
			'[' => { tokens.push(Token::LBracket); 1 },
			']' => { tokens.push(Token::RBracket); 1 },
			'{' => { tokens.push(Token::LBrace); 1 },
			'}' => { tokens.push(Token::RBrace); 1 },
			':' => { tokens.push(Token::Colon); 1 },
			'\'' => { tokens.push(Token::Quote); 1 },
			c if c.is_numeric() => {
				let end_i = word.find(|c: char| !c.is_numeric() && c != '.' && c != '_')
					.unwrap_or(word.len());
				tokens.push(Token::Number(&word[..end_i]));

				end_i
			},
			c if is_ident_char(c) => {
				let end_i = word.find(|c: char| !is_ident_char(c))
					.map(|end_i| if word[end_i..].starts_with('!') {
						end_i + 1
					} else {
						end_i
					})
					.unwrap_or(word.len());
				tokens.push(Token::Ident(&word[..end_i]));

				end_i
			},
			c => return Err(format!("tokenize_word:: Unexpected character `{}`", c))
		};
		word = &word[shift..];
	}

	Ok(tokens)
}

/// Tokenize any string of code
pub fn tokenize_string(src: &str) -> Result<Vec<Token>, String> {
	match split_by_whitespace(src) {
		Ok(words) => {
			let mut out_tokens = Vec::with_capacity(src.len() / 2);
			for word in words {
				match tokenize_word(word) {
					Ok(tokens) => out_tokens.extend(tokens),
					Err(e) => return Err(e)
				}
			}
			Ok(out_tokens)
		},
		Err(e) => Err(e.into())
	}
}

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

	#[test]
	fn test_split_by_whitespace() {
		let src = r##"(foo _Bar r"b a " r#"s 1 4"# 4_100.125: Xyz"##;
		assert_eq!(&split_by_whitespace(src).unwrap(), &[
			"(foo", "_Bar", r#"r"b a ""#, r##"r#"s 1 4"#"##, "4_100.125:", "Xyz"
		]);
	}

	#[test]
	fn test_tokenize_word() {
		let src = "(:4_100.125)";
		assert_eq!(&tokenize_word(src).unwrap(), &[
			LParen, Colon, Number("4_100.125"), RParen
		]);
	}

	#[test]
	fn test_tokenize_string() {
		let src = r##"(f00 _Bar r"b a " r#"s 1 4"# 4_100.125: Xyz"##;
		assert_eq!(&tokenize_string(src).unwrap(), &[
			LParen,
			Ident("f00"),
			Ident("_Bar"),
			String(r#"r"b a ""#),
			String(r##"r#"s 1 4"#"##),
			Number("4_100.125"),
			Colon,
			Ident("Xyz")
		]);

		let src = r#"[foo?::<T> _bar_)"#;
		assert_eq!(&tokenize_string(src).unwrap(), &[
			LBracket, Ident("foo?"), Colon, Colon, LT, Ident("T"), GT, Ident("_bar_"), RParen
		]);
	}
}
<commit_msg>Rewrite lex module to use on-the-go tokenization via iterator<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2015 Johan Johansson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Token<'a> {
	LParen,
	RParen,
	Ident(&'a str),
	Num(&'a str),
	Str(&'a str),
	Colon,
	Backtick,
}

fn try_tokenize<F>(src: &str, i: usize, f: F) -> (Token, usize)
	where F: Fn(&str) -> Result<(Token, usize), String>
{
	match f(&src[i..]) {
		Ok(x) => x,
		Err(e) => error_in_source_at(src, i, e)
	}
}

fn tokenize_str_lit(src: &str) -> Result<(Token, usize), String> {
	// Assume first char is a double quote
	let mut char_it = src.char_indices();
	char_it.next();

	while let Some((i, c)) = char_it.next() {
		match c {
			'\\' => { char_it.next(); },
			// TODO: Unescape
			'"' => return Ok((Token::Str(&src[1..i]), i)),
			_ => (),
		}
	}
	Err("Unterminated string literal".into())
}
fn tokenize_raw_str_lit(src: &str) -> Result<(Token, usize), String> {
	// Assume first char is an 'r'
	let n_delim_octothorpes = src[1..].chars().take_while(|c| c == '#').count();

	let delim_octothorpes = &src[1 .. 1 + n_delim_octothorpes];

	let mut char_it = src.char_indices();
	char_it.next();

	while let Some((i, c)) = char_it.next() {
		if c == '"' && src[i + 1 ..].starts_with(delim_octothorpes) {
			return Ok((Token::Str(&src[2 + n_delim_octothorpes .. i]), i + 1))
		}
	}
	Err("Unterminated raw string literal".into())
}
fn tokenize_num_lit(src: &str) -> Result<(Token, usize), String> {
	let mut has_decimal_pt = false;
	let mut char_it = src.char_indices();

	for (i, c) in  {
		// TODO: Add 'E' notation, e.g. 3.14E10, 5E-4
		match c {
			'_' | _ if c.is_numeric() => (),
			'.' if !has_decimal_pt => has_decimal_pt = true,
			_ => return Ok((Token::Num(&src[..i]), i)),
		}
	}
	Err("Invalid numeric literal".into())
}
fn tokenize_ident(src: &str) -> Result<(Token, usize), String> {
	// Assume first characted has already been checked to be valid
	for (i, c) in src.char_indices() {
		match c {
			')' | ']' | '}' => return Ok((Token::Ident(&src[0..i]), i)),
			_ => (),
		}
	}
	Err("Invalid ident".into())
}

struct Tokens<'a> {
	src: &'a str,
	start_i: usize,
}
impl From<&str> for Tokens {
	fn from(src: &str) -> Tokens { Tokens{ src: src, debug_src_i: 0 } }
}
impl Iterator for Tokens {
	type Item = Token;

	fn next(&mut self) -> Option<Token> {
		let mut char_it = self.src[self.start_i..]
			.char_indices()
			.map(|(i, c)| (i + self.start_i, c));

		while let Some((i, c)) in char_it.next() {
			let (t, len) = match c {
				_ if c.is_whitespace() => continue,
				';' => {
					while let Some((_, c)) = char_it.next() {
						if c == '\n' { break; }
					}
					continue
				},
				'`' => (Token::Backtick, 1),
				':' => (Token::Colon, 1),
				'(' => (Token::LParen, 1), ')' => (Token::RParen, 1),
				'"' => try_tokenize(self.src, i, tokenize_str_lit),
				'r' if self.src[i + 1 ..].starts_with(|c: char| c == '"' || c == '#') =>
					try_tokenize(self.src, i, tokenize_raw_str_lit),
				_ if c.is_numeric() =>
					try_tokenize(self.src, i, tokenize_num_lit),
				_ => try_tokenize(self.src, i, tokenize_ident),
			};

			self.start_i = i + len;
			return Some(t);
		}
		None
	}
}

#[cfg(test)]
mod test {
	use super::*;
	use super::Token::*;
}
<|endoftext|>


<commit_before>use std::fmt;
use std::vec::Vec;
use {success, Matcher, MatchResult};

#[derive(Clone,Copy)]
pub struct OfLen {
    len: usize
}

impl fmt::Display for OfLen {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "of len {}", self.len)
    }
}

impl<'a, T> Matcher<&'a Vec<T>> for OfLen {
    fn matches(&self, actual: &Vec<T>) -> MatchResult {
        if self.len == actual.len() {
            success()
        } else {
            Err(format!("was len {}", actual.len()))
        }
    }
}

pub fn of_len(len: usize) -> Box<OfLen> {
    Box::new(OfLen { len: len })
}

#[derive(Clone)]
pub struct Contains<T> {
    items: Vec<T>,
    exactly: bool
}

impl<T> Contains<T> {
    pub fn exactly(mut self) -> Contains<T> {
        self.exactly = true;
        self
    }
}

impl<T: fmt::Debug> fmt::Display for Contains<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.exactly {
            write!(f, "containing exactly {}", Pretty(&self.items))
        } else {
            write!(f, "containing {}", Pretty(&self.items))
        }
    }
}

impl<'a, T: fmt::Debug + PartialEq + Clone> Matcher<&'a Vec<T>> for Contains<T> {
    fn matches(&self, actual: &Vec<T>) -> MatchResult {
        let mut rem = actual.clone();

        for item in self.items.iter() {
            match rem.iter().position(|a| *item == *a) {
                Some(idx) => { rem.remove(idx); },
                None => return Err(format!("was {}", Pretty(&actual)))
            }
        }

        if self.exactly && !rem.is_empty() {
            return Err(format!("also had {}", Pretty(&rem)));
        }

        success()
    }
}

pub fn contains<T>(items: Vec<T>) -> Contains<T> {
    Contains { items: items, exactly: false }
}

struct Pretty<'a, T: 'a>(&'a [T]);

impl<'a, T: fmt::Debug> fmt::Display for Pretty<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "["));
        for (i, t) in self.0.iter().enumerate() {
            if i != 0 { try!(write!(f, ", ")); }
            try!(write!(f, "{:?}", t));
        }
        write!(f, "]")
    }
}

#[cfg(test)]
mod test {
    use {
        not,
        assert_that,
        contains
    };

    #[test]
    fn test_vec_contains() {
        assert_that(&vec!(1, 2, 3), contains(vec!(1, 2)));
        assert_that(&vec!(1, 2, 3), not(contains(vec!(4))));
    }

    #[test]
    fn test_vec_contains_exactly() {
        assert_that(&vec!(1, 2, 3), contains(vec!(1, 2, 3)).exactly());
        assert_that(&vec!(1, 2, 3), not(contains(vec!(1, 2)).exactly()));
    }
}
<commit_msg>Make `of_len` work; add tests.<commit_after>use std::fmt;
use std::vec::Vec;
use {success, Matcher, MatchResult};

#[derive(Clone,Copy)]
pub struct OfLen {
    len: usize
}

impl fmt::Display for OfLen {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "of len {}", self.len)
    }
}

impl<'a, T> Matcher<&'a Vec<T>> for OfLen {
    fn matches(&self, actual: &Vec<T>) -> MatchResult {
        if self.len == actual.len() {
            success()
        } else {
            Err(format!("was len {}", actual.len()))
        }
    }
}

pub fn of_len(len: usize) -> OfLen {
    OfLen { len: len }
}

#[derive(Clone)]
pub struct Contains<T> {
    items: Vec<T>,
    exactly: bool
}

impl<T> Contains<T> {
    pub fn exactly(mut self) -> Contains<T> {
        self.exactly = true;
        self
    }
}

impl<T: fmt::Debug> fmt::Display for Contains<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.exactly {
            write!(f, "containing exactly {}", Pretty(&self.items))
        } else {
            write!(f, "containing {}", Pretty(&self.items))
        }
    }
}

impl<'a, T: fmt::Debug + PartialEq + Clone> Matcher<&'a Vec<T>> for Contains<T> {
    fn matches(&self, actual: &Vec<T>) -> MatchResult {
        let mut rem = actual.clone();

        for item in self.items.iter() {
            match rem.iter().position(|a| *item == *a) {
                Some(idx) => { rem.remove(idx); },
                None => return Err(format!("was {}", Pretty(&actual)))
            }
        }

        if self.exactly && !rem.is_empty() {
            return Err(format!("also had {}", Pretty(&rem)));
        }

        success()
    }
}

pub fn contains<T>(items: Vec<T>) -> Contains<T> {
    Contains { items: items, exactly: false }
}

struct Pretty<'a, T: 'a>(&'a [T]);

impl<'a, T: fmt::Debug> fmt::Display for Pretty<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "["));
        for (i, t) in self.0.iter().enumerate() {
            if i != 0 { try!(write!(f, ", ")); }
            try!(write!(f, "{:?}", t));
        }
        write!(f, "]")
    }
}

#[cfg(test)]
mod test {
    use {
        not,
        assert_that,
        contains,
        of_len,
        is
    };

    #[test]
    fn test_vec_contains() {
        assert_that(&vec!(1, 2, 3), contains(vec!(1, 2)));
        assert_that(&vec!(1, 2, 3), not(contains(vec!(4))));
    }

    #[test]
    fn test_vec_contains_exactly() {
        assert_that(&vec!(1, 2, 3), contains(vec!(1, 2, 3)).exactly());
        assert_that(&vec!(1, 2, 3), not(contains(vec!(1, 2)).exactly()));
    }

    #[test]
    fn test_vec_of_len() {
        assert_that(&vec!(1, 2, 3), of_len(3));
        assert_that(&vec!(1, 2, 3), is(of_len(3)));
    }
}
<|endoftext|>


<commit_before>use rustc_serialize::json::Json;
use rustc_serialize::json;
use matrix::json as mjson;
use std::fmt;

#[derive(Clone, Debug, PartialEq)]
pub struct EventID {
    pub id: String,
    pub homeserver: String
}

impl EventID {
    pub fn from_str(s: &str) -> Self {
        let parts: Vec<&str> = s.split(":").collect();
        EventID {
            id: parts[0][1..].to_string(),
            homeserver: parts[1].to_string()
        }
    }
}

#[derive(Clone, Debug)]
pub struct UserID {
    pub nickname: String,
    pub homeserver: String
}

impl UserID {
    pub fn from_str(s: &str) -> Self {
        let parts: Vec<&str> = s.split(":").collect();
        UserID {
            nickname: parts[0][1..].to_string(),
            homeserver: parts[1].to_string()
        }
    }
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct RoomID {
    pub id: String,
    pub homeserver: String
}

impl fmt::Display for RoomID {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "!{}:{}", self.id, self.homeserver)
    }
}

impl RoomID {
    pub fn from_str(s: &str) -> Self {
        let parts: Vec<&str> = s.split(":").collect();
        RoomID {
            id: parts[0][1..].to_string(),
            homeserver: parts[1].to_string()
        }
    }
}

#[derive(Debug)]
pub enum MembershipAction {
    Join
}

impl MembershipAction {
    pub fn from_str(s: &str) -> Self {
        match s {
            "join" => MembershipAction::Join,
            _ => panic!("unknown membership action {:?}", s)
        }
    }
}

#[derive(Debug)]
pub enum RoomEvent {
    CanonicalAlias(String),
    JoinRules(String),
    Membership(UserID, MembershipAction),
    HistoryVisibility(String),
    Create,
    Aliases,
    Message(UserID, String),
    PowerLevels
}

#[derive(Debug)]
pub struct TypingEvent {
    pub users: Vec<UserID>,
    pub room: RoomID,
}

#[derive(Debug)]
pub enum EventData {
    Room(RoomID, RoomEvent),
    Typing(TypingEvent),
    Presence(PresenceEvent)
}

impl EventData {
    pub fn type_str(&self) -> &'static str {
        match self {
            &EventData::Room(_, RoomEvent::Message(_, _)) => {
                "m.room.message"
            },
            _ => unreachable!()
        }
    }

    pub fn to_json(&self) -> json::Json {
        let mut ret = json::Object::new();
        match self {
            &EventData::Room(ref id, ref evt) => {
                match evt {
                    &RoomEvent::Message(ref sender, ref text) => {
                        ret.insert("msgtype".to_string(), json::Json::String("m.text".to_string()));
                        ret.insert("body".to_string(), json::Json::String(text.clone()));
                    },
                    _ => unreachable!()
                }
            },
            _ => unreachable!()
        }
        json::Json::Object(ret)
    }
}

#[derive(Debug)]
pub struct Event {
    pub id: Option<EventID>,
    pub data: EventData
}

#[derive(Debug)]
pub struct PresenceEvent {
    pub presence: String,
    pub user: UserID
}

impl Event {
    pub fn from_json(json: &Json) -> Self {
        let tokens: Vec<&str> = mjson::string(json, "type").trim().split(".").collect();
        assert!(tokens[0] == "m");
        let id = match json.as_object().unwrap().get("event_id") {
            Some(i) => Some(EventID::from_str(i.as_string().unwrap())),
            None => None
        };
        Event {
            id: id,
            data: match tokens[1] {
                "room" =>
                    Self::from_room_json(tokens[2], json),
                "typing" =>
                    EventData::Typing(TypingEvent {
                        users: vec![],
                        room: RoomID::from_str(mjson::string(json, "room_id"))
                    }),
                "presence" =>
                    EventData::Presence(PresenceEvent{
                        presence: mjson::string(json, "content.presence").to_string(),
                        user: UserID::from_str(mjson::string(json, "content.user_id"))
                    }),
                e => panic!("Unknown event {:?}!\nRaw JSON: {:?}", e, json)
            }
        }
    }

    fn from_room_json(event_type: &str, json: &Json) -> EventData {
        EventData::Room(
            RoomID::from_str(mjson::string(json, "room_id")),
            match event_type {
                "canonical_alias" =>
                    RoomEvent::CanonicalAlias(mjson::string(json, "content.alias").to_string()),
                "join_rules" =>
                    RoomEvent::JoinRules(mjson::string(json, "content.join_rule").to_string()),
                "member" =>
                    RoomEvent::Membership(UserID::from_str(mjson::string(json, "user_id")), MembershipAction::from_str(mjson::string(json, "content.membership"))),
                "history_visibility" =>
                    RoomEvent::HistoryVisibility(mjson::string(json, "content.history_visibility").to_string()),
                "create" =>
                    RoomEvent::Create,
                "aliases" =>
                    RoomEvent::Aliases,
                "power_levels" =>
                    RoomEvent::PowerLevels,
                "message" =>
                    RoomEvent::Message(UserID::from_str(mjson::string(json, "user_id")), mjson::string(json, "content.body").to_string()),
                e => panic!("Unknown room event {:?}: {:?}", e, json)
            }
        )
    }
}
<commit_msg>matrix: events: support more membership actions<commit_after>use rustc_serialize::json::Json;
use rustc_serialize::json;
use matrix::json as mjson;
use std::fmt;

#[derive(Clone, Debug, PartialEq)]
pub struct EventID {
    pub id: String,
    pub homeserver: String
}

impl EventID {
    pub fn from_str(s: &str) -> Self {
        let parts: Vec<&str> = s.split(":").collect();
        EventID {
            id: parts[0][1..].to_string(),
            homeserver: parts[1].to_string()
        }
    }
}

#[derive(Clone, Debug)]
pub struct UserID {
    pub nickname: String,
    pub homeserver: String
}

impl UserID {
    pub fn from_str(s: &str) -> Self {
        let parts: Vec<&str> = s.split(":").collect();
        UserID {
            nickname: parts[0][1..].to_string(),
            homeserver: parts[1].to_string()
        }
    }
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct RoomID {
    pub id: String,
    pub homeserver: String
}

impl fmt::Display for RoomID {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "!{}:{}", self.id, self.homeserver)
    }
}

impl RoomID {
    pub fn from_str(s: &str) -> Self {
        let parts: Vec<&str> = s.split(":").collect();
        RoomID {
            id: parts[0][1..].to_string(),
            homeserver: parts[1].to_string()
        }
    }
}

#[derive(Debug)]
pub enum MembershipAction {
    Join,
    Leave,
    Ban,
    Invite,
}

impl MembershipAction {
    pub fn from_str(s: &str) -> Self {
        match s {
            "join" => MembershipAction::Join,
            "leave" => MembershipAction::Leave,
            "ban" => MembershipAction::Ban,
            "invite" => MembershipAction::Invite,
            _ => panic!("unknown membership action {:?}", s)
        }
    }
}

#[derive(Debug)]
pub enum RoomEvent {
    CanonicalAlias(String),
    JoinRules(String),
    Membership(UserID, MembershipAction),
    HistoryVisibility(String),
    Create,
    Aliases,
    Message(UserID, String),
    PowerLevels
}

#[derive(Debug)]
pub struct TypingEvent {
    pub users: Vec<UserID>,
    pub room: RoomID,
}

#[derive(Debug)]
pub enum EventData {
    Room(RoomID, RoomEvent),
    Typing(TypingEvent),
    Presence(PresenceEvent)
}

impl EventData {
    pub fn type_str(&self) -> &'static str {
        match self {
            &EventData::Room(_, RoomEvent::Message(_, _)) => {
                "m.room.message"
            },
            _ => unreachable!()
        }
    }

    pub fn to_json(&self) -> json::Json {
        let mut ret = json::Object::new();
        match self {
            &EventData::Room(ref id, ref evt) => {
                match evt {
                    &RoomEvent::Message(ref sender, ref text) => {
                        ret.insert("msgtype".to_string(), json::Json::String("m.text".to_string()));
                        ret.insert("body".to_string(), json::Json::String(text.clone()));
                    },
                    _ => unreachable!()
                }
            },
            _ => unreachable!()
        }
        json::Json::Object(ret)
    }
}

#[derive(Debug)]
pub struct Event {
    pub id: Option<EventID>,
    pub data: EventData
}

#[derive(Debug)]
pub struct PresenceEvent {
    pub presence: String,
    pub user: UserID
}

impl Event {
    pub fn from_json(json: &Json) -> Self {
        let tokens: Vec<&str> = mjson::string(json, "type").trim().split(".").collect();
        assert!(tokens[0] == "m");
        let id = match json.as_object().unwrap().get("event_id") {
            Some(i) => Some(EventID::from_str(i.as_string().unwrap())),
            None => None
        };
        Event {
            id: id,
            data: match tokens[1] {
                "room" =>
                    Self::from_room_json(tokens[2], json),
                "typing" =>
                    EventData::Typing(TypingEvent {
                        users: vec![],
                        room: RoomID::from_str(mjson::string(json, "room_id"))
                    }),
                "presence" =>
                    EventData::Presence(PresenceEvent{
                        presence: mjson::string(json, "content.presence").to_string(),
                        user: UserID::from_str(mjson::string(json, "content.user_id"))
                    }),
                e => panic!("Unknown event {:?}!\nRaw JSON: {:?}", e, json)
            }
        }
    }

    fn from_room_json(event_type: &str, json: &Json) -> EventData {
        EventData::Room(
            RoomID::from_str(mjson::string(json, "room_id")),
            match event_type {
                "canonical_alias" =>
                    RoomEvent::CanonicalAlias(mjson::string(json, "content.alias").to_string()),
                "join_rules" =>
                    RoomEvent::JoinRules(mjson::string(json, "content.join_rule").to_string()),
                "member" =>
                    RoomEvent::Membership(UserID::from_str(mjson::string(json, "user_id")), MembershipAction::from_str(mjson::string(json, "content.membership"))),
                "history_visibility" =>
                    RoomEvent::HistoryVisibility(mjson::string(json, "content.history_visibility").to_string()),
                "create" =>
                    RoomEvent::Create,
                "aliases" =>
                    RoomEvent::Aliases,
                "power_levels" =>
                    RoomEvent::PowerLevels,
                "message" =>
                    RoomEvent::Message(UserID::from_str(mjson::string(json, "user_id")), mjson::string(json, "content.body").to_string()),
                e => panic!("Unknown room event {:?}: {:?}", e, json)
            }
        )
    }
}
<|endoftext|>


<commit_before>extern crate ffmpeg;

use std::path::Path;

use std::rc::Weak;
use std::rc::Rc;
use std::cell::RefCell;

pub trait VideoNotifiable {
    fn new_video_frame(&mut self, ffmpeg::frame::Video);
}
pub trait AudioNotifiable {
    fn new_audio_frame(&mut self, ffmpeg::frame::Audio);
}

pub struct Context {
    pub ffmpeg_context: ffmpeg::format::context::Input,
    pub path: String,
    pub name: String,
    pub description: String,

    pub video_stream: Option<usize>,
    pub video_decoder: Option<ffmpeg::codec::decoder::Video>,
    pub video_notifiable: Option<Weak<RefCell<VideoNotifiable>>>,

    pub audio_stream: Option<usize>,
    pub audio_decoder: Option<ffmpeg::codec::decoder::Audio>,
    pub audio_notifiable: Option<Weak<RefCell<AudioNotifiable>>>,
}

fn print_packet_content(stream: &ffmpeg::format::stream::Stream, packet: &ffmpeg::codec::packet::Packet) {
    println!("\n* Packet for {:?} stream: {}", stream.disposition(), stream.index());
    println!("\tsize: {} - duration: {}, is key: {}",
             packet.size(), packet.duration(), packet.is_key(),
    );
    match packet.pts() {
        Some(pts) => println!("\tpts: {}", pts),
        None => (),
    }
    match packet.dts() {
        Some(dts) => println!("\tdts: {}", dts),
        None => (),
    }
    if let Some(data) = packet.data() {
        println!("\tfound data with len: {}", data.len());
    }
    let side_data_iter = stream.side_data();
    let side_data_len = side_data_iter.size_hint().0;
    if side_data_len > 0 {
        println!("\tside data nb: {}", side_data_len);
    }

    let decoder = stream.codec().decoder();
    match decoder.medium() {
        ffmpeg::media::Type::Video => match decoder.video() {
            Ok(video) => println!("\tvideo decoder: {:?}, width: {}, height: {}",
                                  video.format(), video.width(), video.height()),
            Err(_) => (),
        },
        ffmpeg::media::Type::Audio => match decoder.audio() {
            Ok(audio) => println!("\taudio decoder: {:?}, channels: {}, frame count: {}",
                                  audio.format(), audio.channels(), audio.frames()),
            Err(_) => (),
        },
        _ => (),
    }
}

impl Context {
    pub fn new(path: &Path) -> Result<Context, String> {
        match ffmpeg::format::input(&path) {
            Ok(ffmpeg_context) => {
                let mut new_ctx = Context{
                    ffmpeg_context: ffmpeg_context,
                    path: String::from(path.to_str().unwrap()),
                    name: String::new(),
                    description: String::new(),

                    video_stream: None,
                    video_decoder: None,
                    video_notifiable: None,

                    audio_stream: None,
                    audio_decoder: None,
                    audio_notifiable: None,
                };

                {
                    let format = new_ctx.ffmpeg_context.format();
                    new_ctx.name = String::from(format.name());
                    new_ctx.description = String::from(format.description());

                    new_ctx.init_video_decoder();
                    new_ctx.init_audio_decoder();
                }

                // TODO: process metadata

                // TODO: see what we should do with subtitles

                println!("\n*** New media - Input: {} - {}", &new_ctx.name, &new_ctx.description);

                //new_ctx.preview();

                if new_ctx.video_stream.is_some() || new_ctx.audio_stream.is_some() {
                    // TODO: also check for misdetections (detection score)
                    Ok(new_ctx)
                }
                else {
                    Err("Couldn't find any video or audio stream".to_owned())
                }
            },
            Err(error) => {
                Err(format!("{:?}", error))
            },
        }
    }

    pub fn init_video_decoder(&mut self) {
        let stream = match self.ffmpeg_context.streams().best(ffmpeg::media::Type::Video) {
            Some(best_stream) => {
                println!("\nFound video stream with id: {}", best_stream.index());
                best_stream
            },
            None => {
                println!("No video stream");
                return;
            },
        };

        match stream.codec().decoder().video() {
            Ok(mut decoder) => {
                match decoder.set_parameters(stream.parameters()) {
                    Ok(_) => {
                        println!("\tinitialzed video decoder: {:?}", decoder.format());
                    },
                    Err(error) => panic!("Failed to set parameters for video decoder: {:?}", error),
                }

                self.video_stream = Some(stream.index());
                self.video_decoder = Some(decoder);
            },
            Err(error) => panic!("Failed to get video decoder: {:?}", error),
        }
    }

    pub fn init_audio_decoder(&mut self) {
        let stream = match self.ffmpeg_context.streams().best(ffmpeg::media::Type::Audio) {
            Some(best_stream) => {
                println!("\nFound audio stream with id: {}", best_stream.index());
                best_stream
            },
            None => {
                println!("No audio stream");
                return;
            },
        };

        match stream.codec().decoder().audio() {
            Ok(mut decoder) => {
                match decoder.set_parameters(stream.parameters()) {
                    Ok(_) => {
                        println!("\tinitialzed audio decoder: {:?} - channels: {}", decoder.format(), decoder.channels());
                    },
                    Err(error) => panic!("Failed to set parameters for audio decoder: {:?}", error),
                }

                self.audio_stream = Some(stream.index());
                self.audio_decoder = Some(decoder);
            },
            Err(error) => panic!("Failed to get audio decoder: {:?}", error),
        }
    }

    pub fn register_video_notifiable(&mut self, notifiable: Rc<RefCell<VideoNotifiable>>) {
        self.video_notifiable = Some(Rc::downgrade(&notifiable));
    }

    pub fn register_audio_notifiable(&mut self, notifiable: Rc<RefCell<AudioNotifiable>>) {
        self.audio_notifiable = Some(Rc::downgrade(&notifiable));
    }

    pub fn preview(&mut self) {
        // TODO: better trace streams processed (use a HashSet as before)
        let mut frames_processed = 0;
        let mut expected_frames = 0;
        if self.video_stream.is_some() {
            expected_frames += 1;
        }
        if self.audio_stream.is_some() {
            expected_frames += 1;
        }

        let mut video_frame = ffmpeg::frame::Video::empty();
        let mut audio_frame = ffmpeg::frame::Audio::empty();

        for (stream, packet) in self.ffmpeg_context.packets() {
            //print_packet_content(&stream, &packet); // TODO: fix this function which corrupts the decoder
            let mut got_frame = false;
            let decoder = stream.codec().decoder();
            match decoder.medium() {
                ffmpeg::media::Type::Video => match self.video_stream {
                    Some(stream_index) => {
                        if stream_index == stream.index() {
                            let mut video = match self.video_decoder {
                                Some(ref mut decoder) => decoder,
                                None => panic!("Error getting video decoder for stream {}", stream_index),
                            };
                            match video.decode(&packet, &mut video_frame) {
                                Ok(decode_got_frame) =>  {
                                    got_frame = decode_got_frame;
                                    let planes = video_frame.planes();
                                    println!("\tdecoded video frame, found {} planes - got frame: {}", planes, got_frame);
                                    for index in 0..planes {
                                        println!("\tplane: {} - data len: {}", index, video_frame.data(index).len());
                                    }
                                },
                                Err(error) => println!("Error decoding video packet for stream {}: {:?}", stream_index, error),
                            }
                            if got_frame {
                                frames_processed += 1;
                                match self.video_notifiable.as_ref() {
                                    Some(notifiable_weak) => {
                                        match notifiable_weak.upgrade() {
                                            Some(notifiable) => {
                                                notifiable.borrow_mut().new_video_frame(video_frame);
                                                video_frame = ffmpeg::frame::Video::empty();
                                            },
                                            None => (),
                                        }
                                    },
                                    None => (),
                                }
                            }
                        }
                        else {
                            println!("Skipping stream {}", stream.index());
                        }
                    },
                    None => panic!("No video decoder"),
                },
                ffmpeg::media::Type::Audio => match self.audio_stream {
                    Some(stream_index) => {
                        if stream_index == stream.index() {
                            let ref mut audio = match self.audio_decoder.as_mut() {
                                Some(decoder) => decoder,
                                None => panic!("Error getting audio decoder for stream {}", stream_index),
                            };
                            match audio.decode(&packet, &mut audio_frame) {
                                Ok(decode_got_frame) =>  {
                                    got_frame = decode_got_frame;
                                    let planes = audio_frame.planes();
                                    println!("\tdecoded audio frame, found {} planes - got frame: {}", planes, got_frame);
                                    for index in 0..planes {
                                        println!("\tplane: {} - data len: {}", index, audio_frame.data(index).len());
                                    }
                                },
                                Err(error) => panic!("Error decoding audio packet for stream {}: {:?}", stream_index, error),
                            }
                            if got_frame {
                                frames_processed += 1;
                                match self.audio_notifiable.as_ref() {
                                    Some(notifiable_weak) => {
                                        match notifiable_weak.upgrade() {
                                            Some(notifiable) => {
                                                notifiable.borrow_mut().new_audio_frame(audio_frame);
                                                audio_frame = ffmpeg::frame::Audio::empty();
                                            },
                                            None => (),
                                        }
                                    },
                                    None => (),
                                }
                            }
                        }
                        else {
                            println!("Skipping stream {}", stream.index());
                        }
                    },
                    None => panic!("No audio decoder"),
                },
                _ => (),
            }

            if frames_processed == expected_frames {
                break;
            }
        }
    }
}
<commit_msg>Fixed packet trace (#1)<commit_after>extern crate ffmpeg;

use std::path::Path;

use std::rc::Weak;
use std::rc::Rc;
use std::cell::RefCell;

pub trait VideoNotifiable {
    fn new_video_frame(&mut self, ffmpeg::frame::Video);
}
pub trait AudioNotifiable {
    fn new_audio_frame(&mut self, ffmpeg::frame::Audio);
}

pub struct Context {
    pub ffmpeg_context: ffmpeg::format::context::Input,
    pub path: String,
    pub name: String,
    pub description: String,

    pub video_stream: Option<usize>,
    pub video_decoder: Option<ffmpeg::codec::decoder::Video>,
    pub video_notifiable: Option<Weak<RefCell<VideoNotifiable>>>,

    pub audio_stream: Option<usize>,
    pub audio_decoder: Option<ffmpeg::codec::decoder::Audio>,
    pub audio_notifiable: Option<Weak<RefCell<AudioNotifiable>>>,
}

fn print_packet_content(stream: &ffmpeg::format::stream::Stream, packet: &ffmpeg::codec::packet::Packet) {
    println!("\n* Packet for {:?} stream: {}", stream.disposition(), stream.index());
    println!("\tsize: {} - duration: {}, is key: {}",
             packet.size(), packet.duration(), packet.is_key(),
    );
    match packet.pts() {
        Some(pts) => println!("\tpts: {}", pts),
        None => (),
    }
    match packet.dts() {
        Some(dts) => println!("\tdts: {}", dts),
        None => (),
    }
    if let Some(ref data) = packet.data() {
        println!("\tfound data with len: {}", data.len());
    }
    let side_data_iter = stream.side_data();
    let side_data_len = side_data_iter.size_hint().0;
    if side_data_len > 0 {
        println!("\tside data nb: {}", side_data_len);
    }
}

impl Context {
    pub fn new(path: &Path) -> Result<Context, String> {
        match ffmpeg::format::input(&path) {
            Ok(ffmpeg_context) => {
                let mut new_ctx = Context{
                    ffmpeg_context: ffmpeg_context,
                    path: String::from(path.to_str().unwrap()),
                    name: String::new(),
                    description: String::new(),

                    video_stream: None,
                    video_decoder: None,
                    video_notifiable: None,

                    audio_stream: None,
                    audio_decoder: None,
                    audio_notifiable: None,
                };

                {
                    let format = new_ctx.ffmpeg_context.format();
                    new_ctx.name = String::from(format.name());
                    new_ctx.description = String::from(format.description());

                    new_ctx.init_video_decoder();
                    new_ctx.init_audio_decoder();
                }

                // TODO: process metadata

                // TODO: see what we should do with subtitles

                println!("\n*** New media - Input: {} - {}", &new_ctx.name, &new_ctx.description);

                //new_ctx.preview();

                if new_ctx.video_stream.is_some() || new_ctx.audio_stream.is_some() {
                    // TODO: also check for misdetections (detection score)
                    Ok(new_ctx)
                }
                else {
                    Err("Couldn't find any video or audio stream".to_owned())
                }
            },
            Err(error) => {
                Err(format!("{:?}", error))
            },
        }
    }

    pub fn init_video_decoder(&mut self) {
        let stream_index;
        let stream = match self.ffmpeg_context.streams().best(ffmpeg::media::Type::Video) {
            Some(best_stream) => {
                stream_index = best_stream.index();
                println!("\nFound video stream with id: {}", stream_index);
                best_stream
            },
            None => {
                println!("No video stream");
                return;
            },
        };

        match stream.codec().decoder().video() {
            Ok(mut decoder) => {
                match decoder.set_parameters(stream.parameters()) {
                    Ok(_) => {
                        println!("\tinitialzed video decoder: {:?}", decoder.format());
                    },
                    Err(error) => panic!("Failed to set parameters for video decoder: {:?}", error),
                }

                println!("\tvideo decoder: {:?}, width: {}, height: {}",
                         decoder.format(), decoder.width(), decoder.height());
                self.video_stream = Some(stream_index);
                self.video_decoder = Some(decoder);
            },
            Err(error) => panic!("Failed to get video decoder: {:?}", error),
        }
    }

    pub fn init_audio_decoder(&mut self) {
        let stream_index;
        let stream = match self.ffmpeg_context.streams().best(ffmpeg::media::Type::Audio) {
            Some(best_stream) => {
                stream_index = best_stream.index();
                println!("\nFound audio stream with id: {}", stream_index);
                best_stream
            },
            None => {
                println!("No audio stream");
                return;
            },
        };

        match stream.codec().decoder().audio() {
            Ok(mut decoder) => {
                match decoder.set_parameters(stream.parameters()) {
                    Ok(_) => {
                        println!("\tinitialzed audio decoder: {:?} - channels: {}", decoder.format(), decoder.channels());
                    },
                    Err(error) => panic!("Failed to set parameters for audio decoder: {:?}", error),
                }
                println!("\taudio decoder: {:?}, channels: {}, frame count: {}",
                         decoder.format(), decoder.channels(), decoder.frames());
                self.audio_stream = Some(stream_index);
                self.audio_decoder = Some(decoder);
            },
            Err(error) => panic!("Failed to get audio decoder: {:?}", error),
        }
    }

    pub fn register_video_notifiable(&mut self, notifiable: Rc<RefCell<VideoNotifiable>>) {
        self.video_notifiable = Some(Rc::downgrade(&notifiable));
    }

    pub fn register_audio_notifiable(&mut self, notifiable: Rc<RefCell<AudioNotifiable>>) {
        self.audio_notifiable = Some(Rc::downgrade(&notifiable));
    }

    pub fn preview(&mut self) {
        // TODO: better trace streams processed (use a HashSet as before)
        let mut frames_processed = 0;
        let mut expected_frames = 0;
        if self.video_stream.is_some() {
            expected_frames += 1;
        }
        if self.audio_stream.is_some() {
            expected_frames += 1;
        }

        let mut video_frame = ffmpeg::frame::Video::empty();
        let mut audio_frame = ffmpeg::frame::Audio::empty();

        for (stream, packet) in self.ffmpeg_context.packets() {
            print_packet_content(&stream, &packet);
            let mut got_frame = false;
            let decoder = stream.codec().decoder();
            match decoder.medium() {
                ffmpeg::media::Type::Video => match self.video_stream {
                    Some(stream_index) => {
                        if stream_index == stream.index() {
                            let mut video = match self.video_decoder {
                                Some(ref mut decoder) => decoder,
                                None => panic!("Error getting video decoder for stream {}", stream_index),
                            };
                            match video.decode(&packet, &mut video_frame) {
                                Ok(decode_got_frame) =>  {
                                    got_frame = decode_got_frame;
                                    let planes = video_frame.planes();
                                    println!("\tdecoded video frame, found {} planes - got frame: {}", planes, got_frame);
                                    for index in 0..planes {
                                        println!("\tplane: {} - data len: {}", index, video_frame.data(index).len());
                                    }
                                },
                                Err(error) => println!("Error decoding video packet for stream {}: {:?}", stream_index, error),
                            }
                            if got_frame {
                                frames_processed += 1;
                                match self.video_notifiable.as_ref() {
                                    Some(notifiable_weak) => {
                                        match notifiable_weak.upgrade() {
                                            Some(notifiable) => {
                                                notifiable.borrow_mut().new_video_frame(video_frame);
                                                video_frame = ffmpeg::frame::Video::empty();
                                            },
                                            None => (),
                                        }
                                    },
                                    None => (),
                                }
                            }
                        }
                        else {
                            println!("Skipping stream {}", stream.index());
                        }
                    },
                    None => panic!("No video decoder"),
                },
                ffmpeg::media::Type::Audio => match self.audio_stream {
                    Some(stream_index) => {
                        if stream_index == stream.index() {
                            let ref mut audio = match self.audio_decoder.as_mut() {
                                Some(decoder) => decoder,
                                None => panic!("Error getting audio decoder for stream {}", stream_index),
                            };
                            match audio.decode(&packet, &mut audio_frame) {
                                Ok(decode_got_frame) =>  {
                                    got_frame = decode_got_frame;
                                    let planes = audio_frame.planes();
                                    println!("\tdecoded audio frame, found {} planes - got frame: {}", planes, got_frame);
                                    for index in 0..planes {
                                        println!("\tplane: {} - data len: {}", index, audio_frame.data(index).len());
                                    }
                                },
                                Err(error) => panic!("Error decoding audio packet for stream {}: {:?}", stream_index, error),
                            }
                            if got_frame {
                                frames_processed += 1;
                                match self.audio_notifiable.as_ref() {
                                    Some(notifiable_weak) => {
                                        match notifiable_weak.upgrade() {
                                            Some(notifiable) => {
                                                notifiable.borrow_mut().new_audio_frame(audio_frame);
                                                audio_frame = ffmpeg::frame::Audio::empty();
                                            },
                                            None => (),
                                        }
                                    },
                                    None => (),
                                }
                            }
                        }
                        else {
                            println!("Skipping stream {}", stream.index());
                        }
                    },
                    None => panic!("No audio decoder"),
                },
                _ => (),
            }

            if frames_processed == expected_frames {
                break;
            }
        }
    }
}
<|endoftext|>


<commit_before>use range::Range;

use {
    ret_err,
    update,
    MetaReader,
    ParseResult,
    Rule,
};

/// Stores inforamtion about separated by.
pub struct SeparatedBy {
    /// The rule to separate.
    pub rule: Rule,
    /// The rule to separate by.
    pub by: Rule,
    /// Whether the rule must occur at least once.
    pub optional: bool,
    /// Whether the rule can end with separator.
    pub allow_trail: bool,
}

impl SeparatedBy {
    /// Parses rule repeatedly separated by another rule.
    pub fn parse<M>(
        &self,
        meta_reader: &mut M,
        state: &M::State,
        mut chars: &[char],
        start_offset: usize
    ) -> ParseResult<M::State>
        where M: MetaReader
    {
        let mut offset = start_offset;
        let mut state = state.clone();
        let mut first = true;
        let mut opt_error = None;
        loop {
            state = match self.rule.parse(meta_reader, &state, chars, offset) {
                Err(err) => {
                    match (first, self.optional, self.allow_trail) {
                          (true, false, _)
                        | (false, _, false) => {
                            return Err(ret_err(err, opt_error));
                        }
                          (true, true, _)
                        | (false, _, true) => { break; }
                    }
                }
                Ok((range, state, err)) => {
                    update(range, err, &mut chars, &mut offset, &mut opt_error);
                    state
                }
            };
            state = match self.by.parse(meta_reader, &state, chars, offset) {
                Err(err) => { opt_error = Some(err); break; }
                Ok((range, state, err)) => {
                    update(range, err, &mut chars, &mut offset, &mut opt_error);
                    state
                }
            };
            first = false;
        }
        Ok((Range::new(start_offset, offset - start_offset), state, opt_error))
    }
}

#[cfg(test)]
mod tests {
    use super::super::*;
    use std::rc::Rc;
    use range::Range;

    #[test]
    fn required() {
        let text = "foo()";
        let chars: Vec<char> = text.chars().collect();
        let mut tokenizer = Tokenizer::new();
        let s = TokenizerState::new();
        let sep = SeparatedBy {
            rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
                any_characters: Rc::new(",)".into()),
                optional: false,
                property: None,
            }),
            by: Rule::Token(Token {
                text: Rc::new(",".into()),
                inverted: false,
                property: None,
            }),
            optional: false,
            allow_trail: false,
        };
        let res = sep.parse(&mut tokenizer, &s, &chars[4..], 4);
        assert_eq!(res, Err((Range::new(4, 0), ParseError::ExpectedSomething)));
    }

    #[test]
    fn optional() {
        let text = "foo()";
        let chars: Vec<char> = text.chars().collect();
        let mut tokenizer = Tokenizer::new();
        let s = TokenizerState::new();
        let sep = SeparatedBy {
            rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
                any_characters: Rc::new(",)".into()),
                optional: false,
                property: None,
            }),
            by: Rule::Token(Token {
                text: Rc::new(",".into()),
                inverted: false,
                property: None,
            }),
            optional: true,
            allow_trail: false,
        };
        let res = sep.parse(&mut tokenizer, &s, &chars[4..], 4);
        assert_eq!(res, Ok((Range::new(4, 0), s, None)));
    }

    #[test]
    fn disallow_trail() {
        let text = "foo(a,b,c,)";
        let chars: Vec<char> = text.chars().collect();
        let mut tokenizer = Tokenizer::new();
        let s = TokenizerState::new();
        let arg: Rc<String> = Rc::new("arg".into());
        let sep = SeparatedBy {
            rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
                any_characters: Rc::new(",)".into()),
                optional: false,
                property: Some(arg.clone()),
            }),
            by: Rule::Token(Token {
                text: Rc::new(",".into()),
                inverted: false,
                property: None,
            }),
            optional: true,
            allow_trail: false,
        };
        let res = sep.parse(&mut tokenizer, &s, &chars[4..], 4);
        assert_eq!(res, Err((Range::new(10, 0), ParseError::ExpectedSomething)));
    }

    #[test]
    fn allow_trail() {
        let text = "foo(a,b,c,)";
        let chars: Vec<char> = text.chars().collect();
        let mut tokenizer = Tokenizer::new();
        let s = TokenizerState::new();
        let arg: Rc<String> = Rc::new("arg".into());
        let sep = SeparatedBy {
            rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
                any_characters: Rc::new(",)".into()),
                optional: false,
                property: Some(arg.clone()),
            }),
            by: Rule::Token(Token {
                text: Rc::new(",".into()),
                inverted: false,
                property: None,
            }),
            optional: true,
            allow_trail: true,
        };
        let res = sep.parse(&mut tokenizer, &s, &chars[4..], 4);
        assert_eq!(res, Ok((Range::new(4, 6), TokenizerState(3), None)));
        assert_eq!(tokenizer.tokens.len(), 3);
        assert_eq!(&tokenizer.tokens[0].0,
            &MetaData::String(arg.clone(), "a".into()));
        assert_eq!(&tokenizer.tokens[1].0,
            &MetaData::String(arg.clone(), "b".into()));
        assert_eq!(&tokenizer.tokens[2].0,
            &MetaData::String(arg.clone(), "c".into()));
    }

    #[test]
    fn successful() {
        let text = "foo(a,b,c)";
        let chars: Vec<char> = text.chars().collect();
        let mut tokenizer = Tokenizer::new();
        let s = TokenizerState::new();
        let arg: Rc<String> = Rc::new("arg".into());
        let sep = SeparatedBy {
            rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
                any_characters: Rc::new(",)".into()),
                optional: false,
                property: Some(arg.clone()),
            }),
            by: Rule::Token(Token {
                text: Rc::new(",".into()),
                inverted: false,
                property: None,
            }),
            optional: true,
            allow_trail: false,
        };
        let res = sep.parse(&mut tokenizer, &s, &chars[4..], 4);
        assert_eq!(res, Ok((Range::new(4, 5), TokenizerState(3),
            Some((Range::new(9, 0), ParseError::ExpectedToken(",".into()))))));
        assert_eq!(tokenizer.tokens.len(), 3);
        assert_eq!(&tokenizer.tokens[0].0,
            &MetaData::String(arg.clone(), "a".into()));
        assert_eq!(&tokenizer.tokens[1].0,
            &MetaData::String(arg.clone(), "b".into()));
        assert_eq!(&tokenizer.tokens[2].0,
            &MetaData::String(arg.clone(), "c".into()));
    }
}
<commit_msg>Fixed bug in `SeparatedBy`<commit_after>use range::Range;

use {
    ret_err,
    err_update,
    update,
    MetaReader,
    ParseResult,
    Rule,
};

/// Stores inforamtion about separated by.
pub struct SeparatedBy {
    /// The rule to separate.
    pub rule: Rule,
    /// The rule to separate by.
    pub by: Rule,
    /// Whether the rule must occur at least once.
    pub optional: bool,
    /// Whether the rule can end with separator.
    pub allow_trail: bool,
}

impl SeparatedBy {
    /// Parses rule repeatedly separated by another rule.
    pub fn parse<M>(
        &self,
        meta_reader: &mut M,
        state: &M::State,
        mut chars: &[char],
        start_offset: usize
    ) -> ParseResult<M::State>
        where M: MetaReader
    {
        let mut offset = start_offset;
        let mut state = state.clone();
        let mut first = true;
        let mut opt_error = None;
        loop {
            state = match self.rule.parse(meta_reader, &state, chars, offset) {
                Err(err) => {
                    match (first, self.optional, self.allow_trail) {
                          (true, false, _)
                        | (false, _, false) => {
                            return Err(ret_err(err, opt_error));
                        }
                          (true, true, _)
                        | (false, _, true) => {
                            err_update(Some(err), &mut opt_error);
                            break;
                        }
                    }
                }
                Ok((range, state, err)) => {
                    update(range, err, &mut chars, &mut offset, &mut opt_error);
                    state
                }
            };
            state = match self.by.parse(meta_reader, &state, chars, offset) {
                Err(err) => { opt_error = Some(err); break; }
                Ok((range, state, err)) => {
                    update(range, err, &mut chars, &mut offset, &mut opt_error);
                    state
                }
            };
            first = false;
        }
        Ok((Range::new(start_offset, offset - start_offset), state, opt_error))
    }
}

#[cfg(test)]
mod tests {
    use super::super::*;
    use std::rc::Rc;
    use range::Range;

    #[test]
    fn required() {
        let text = "foo()";
        let chars: Vec<char> = text.chars().collect();
        let mut tokenizer = Tokenizer::new();
        let s = TokenizerState::new();
        let sep = SeparatedBy {
            rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
                any_characters: Rc::new(",)".into()),
                optional: false,
                property: None,
            }),
            by: Rule::Token(Token {
                text: Rc::new(",".into()),
                inverted: false,
                property: None,
            }),
            optional: false,
            allow_trail: false,
        };
        let res = sep.parse(&mut tokenizer, &s, &chars[4..], 4);
        assert_eq!(res, Err((Range::new(4, 0), ParseError::ExpectedSomething)));
    }

    #[test]
    fn optional() {
        let text = "foo()";
        let chars: Vec<char> = text.chars().collect();
        let mut tokenizer = Tokenizer::new();
        let s = TokenizerState::new();
        let sep = SeparatedBy {
            rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
                any_characters: Rc::new(",)".into()),
                optional: false,
                property: None,
            }),
            by: Rule::Token(Token {
                text: Rc::new(",".into()),
                inverted: false,
                property: None,
            }),
            optional: true,
            allow_trail: false,
        };
        let res = sep.parse(&mut tokenizer, &s, &chars[4..], 4);
        assert_eq!(res, Ok((Range::new(4, 0), s,
            Some((Range::new(4, 0), ParseError::ExpectedSomething)))));
    }

    #[test]
    fn disallow_trail() {
        let text = "foo(a,b,c,)";
        let chars: Vec<char> = text.chars().collect();
        let mut tokenizer = Tokenizer::new();
        let s = TokenizerState::new();
        let arg: Rc<String> = Rc::new("arg".into());
        let sep = SeparatedBy {
            rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
                any_characters: Rc::new(",)".into()),
                optional: false,
                property: Some(arg.clone()),
            }),
            by: Rule::Token(Token {
                text: Rc::new(",".into()),
                inverted: false,
                property: None,
            }),
            optional: true,
            allow_trail: false,
        };
        let res = sep.parse(&mut tokenizer, &s, &chars[4..], 4);
        assert_eq!(res, Err((Range::new(10, 0), ParseError::ExpectedSomething)));
    }

    #[test]
    fn allow_trail() {
        let text = "foo(a,b,c,)";
        let chars: Vec<char> = text.chars().collect();
        let mut tokenizer = Tokenizer::new();
        let s = TokenizerState::new();
        let arg: Rc<String> = Rc::new("arg".into());
        let sep = SeparatedBy {
            rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
                any_characters: Rc::new(",)".into()),
                optional: false,
                property: Some(arg.clone()),
            }),
            by: Rule::Token(Token {
                text: Rc::new(",".into()),
                inverted: false,
                property: None,
            }),
            optional: true,
            allow_trail: true,
        };
        let res = sep.parse(&mut tokenizer, &s, &chars[4..], 4);
        assert_eq!(res, Ok((Range::new(4, 6), TokenizerState(3),
            Some((Range::new(10, 0), ParseError::ExpectedSomething)))));
        assert_eq!(tokenizer.tokens.len(), 3);
        assert_eq!(&tokenizer.tokens[0].0,
            &MetaData::String(arg.clone(), "a".into()));
        assert_eq!(&tokenizer.tokens[1].0,
            &MetaData::String(arg.clone(), "b".into()));
        assert_eq!(&tokenizer.tokens[2].0,
            &MetaData::String(arg.clone(), "c".into()));
    }

    #[test]
    fn successful() {
        let text = "foo(a,b,c)";
        let chars: Vec<char> = text.chars().collect();
        let mut tokenizer = Tokenizer::new();
        let s = TokenizerState::new();
        let arg: Rc<String> = Rc::new("arg".into());
        let sep = SeparatedBy {
            rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
                any_characters: Rc::new(",)".into()),
                optional: false,
                property: Some(arg.clone()),
            }),
            by: Rule::Token(Token {
                text: Rc::new(",".into()),
                inverted: false,
                property: None,
            }),
            optional: true,
            allow_trail: false,
        };
        let res = sep.parse(&mut tokenizer, &s, &chars[4..], 4);
        assert_eq!(res, Ok((Range::new(4, 5), TokenizerState(3),
            Some((Range::new(9, 0), ParseError::ExpectedToken(",".into()))))));
        assert_eq!(tokenizer.tokens.len(), 3);
        assert_eq!(&tokenizer.tokens[0].0,
            &MetaData::String(arg.clone(), "a".into()));
        assert_eq!(&tokenizer.tokens[1].0,
            &MetaData::String(arg.clone(), "b".into()));
        assert_eq!(&tokenizer.tokens[2].0,
            &MetaData::String(arg.clone(), "c".into()));
    }
}
<|endoftext|>


<commit_before>mod entities;
mod input;
mod updates;
mod util;

use chrono::{DateTime, Duration as OldDuration, Utc};
use log::{error, trace};
use rand_core::{OsRng, RngCore};
use serde_derive::Serialize;
use std::collections::HashMap;
use std::mem;

pub use self::entities::*;
pub use self::input::*;
pub use self::updates::*;
pub use self::util::*;

use crate::server::{ArenaId, ArenaPoint, Direction, Line, Player, PlayerId};

const ARENA_WIDTH: usize = 800;
const ARENA_HEIGHT: usize = 800;
const ARENA_MAX_PLAYERS: usize = 8;
const ARENA_START_TIMER_SECONDS: i64 = 5;
const LIGHTCYCLE_SPEED: isize = 120;

#[derive(Debug, Clone, Serialize)]
pub struct Arena {
    pub id: ArenaId,
    pub width: usize,
    pub height: usize,
    pub max_players: usize,

    pub started: Option<DateTime<Utc>>,

    pub players: HashMap<PlayerId, Player>,
    pub lightcycles: HashMap<PlayerId, Lightcycle>,
    pub trails: HashMap<PlayerId, Trail>,

    #[serde(skip)]
    pub updates: Vec<ArenaUpdate>,
    #[serde(skip)]
    updates_applied_so_far: usize,
}

impl Arena {
    pub fn add_player(&mut self, player: Player) {
        self.updates.push(ArenaUpdate::AddPlayer(player.id, player));
    }

    pub fn remove_player(&mut self, player_id: PlayerId) {
        self.updates.push(ArenaUpdate::RemovePlayer(player_id));
    }

    pub fn clear_updates(&mut self) {
        self.updates.clear();
        self.updates_applied_so_far = 0;
    }

    pub fn apply_updates(&mut self) -> &mut Self {
        let updates = mem::replace(&mut self.updates, Vec::new());
        for update in updates.iter().skip(self.updates_applied_so_far) {
            update.apply(self);
            self.updates_applied_so_far += 1;
        }
        mem::replace(&mut self.updates, updates);

        self
    }

    pub fn process_input(&mut self, player_id: PlayerId, input_event: ArenaInput) {
        input_event
            .process_into_updates(self, player_id)
            .drain(..)
            .for_each(|update| self.updates.push(update));
    }

    pub fn update(&mut self) {
        // apply process_input updates
        self.apply_updates();

        let started = match self.started {
            Some(started) => started,
            None => return,
        };

        let now = Utc::now();
        if now < started {
            return;
        }

        self.update_lightcycle_positions()
            .apply_updates()
            .update_trail_positions()
            .apply_updates()
            .calculate_lightcycle_collisions()
            .apply_updates();
    }

    //
    // update helpers
    //

    fn update_lightcycle_positions(&mut self) -> &mut Self {
        for (id, lightcycle) in self.lightcycles.iter() {
            if lightcycle.dead {
                continue;
            };

            self.updates
                .push(ArenaUpdate::UpdateLightcycleApplyVelocity(*id))
        }
        self
    }

    fn update_trail_positions(&mut self) -> &mut Self {
        for id in self.trails.keys() {
            let latest_point = match self.lightcycles.get(id) {
                Some(lightcycle) => {
                    if lightcycle.dead {
                        continue;
                    };

                    lightcycle.position
                }
                None => {
                    error!(
                        "Failed to update trail position: No lightcycle with id {}",
                        id
                    );
                    continue;
                }
            };

            self.updates
                .push(ArenaUpdate::UpdateTrailReplaceLatestPoint(
                    *id,
                    latest_point,
                ));
        }
        self
    }

    fn calculate_lightcycle_collisions(&mut self) -> &mut Self {
        'next_lightcycle: for (id, lightcycle) in self.lightcycles.iter() {
            if lightcycle.dead {
                continue 'next_lightcycle;
            };

            for trail in self.trails.values() {
                for line in trail.points.windows(2) {
                    let start = line[0];
                    let end = line[1];

                    if is_point_on_line_2d(lightcycle.position, Line(start, end)) {
                        self.updates
                            .push(ArenaUpdate::UpdateLightcycleApplyDeath(*id));
                        continue 'next_lightcycle;
                    }
                }
            }
        }
        self
    }
}

impl Default for Arena {
    fn default() -> Self {
        Self {
            id: ArenaId::new_v4(),
            width: ARENA_WIDTH,
            height: ARENA_HEIGHT,
            max_players: ARENA_MAX_PLAYERS,

            started: None,

            players: Default::default(),
            lightcycles: Default::default(),
            trails: Default::default(),

            updates: Default::default(),
            updates_applied_so_far: 0,
        }
    }
}

/// ArenaOverview represents an overview of an Arena for the arena selection screen.
#[derive(Debug, Clone, Serialize)]
pub struct ArenaOverview {
    id: ArenaId,
    max_players: usize,
    started: Option<DateTime<Utc>>,
    players: HashMap<PlayerId, Player>,
}

impl From<&Arena> for ArenaOverview {
    fn from(arena: &Arena) -> Self {
        Self {
            id: arena.id,
            max_players: arena.max_players,
            started: arena.started,
            players: arena.players.clone(),
        }
    }
}
<commit_msg>fixed lightcycles colliding with the latest point on their own trail<commit_after>mod entities;
mod input;
mod updates;
mod util;

use chrono::{DateTime, Duration as OldDuration, Utc};
use log::{error, trace};
use rand_core::{OsRng, RngCore};
use serde_derive::Serialize;
use std::collections::HashMap;
use std::mem;

pub use self::entities::*;
pub use self::input::*;
pub use self::updates::*;
pub use self::util::*;

use crate::server::{ArenaId, ArenaPoint, Direction, Line, Player, PlayerId};

const ARENA_WIDTH: usize = 800;
const ARENA_HEIGHT: usize = 800;
const ARENA_MAX_PLAYERS: usize = 8;
const ARENA_START_TIMER_SECONDS: i64 = 5;
const LIGHTCYCLE_SPEED: isize = 120;

#[derive(Debug, Clone, Serialize)]
pub struct Arena {
    pub id: ArenaId,
    pub width: usize,
    pub height: usize,
    pub max_players: usize,

    pub started: Option<DateTime<Utc>>,

    pub players: HashMap<PlayerId, Player>,
    pub lightcycles: HashMap<PlayerId, Lightcycle>,
    pub trails: HashMap<PlayerId, Trail>,

    #[serde(skip)]
    pub updates: Vec<ArenaUpdate>,
    #[serde(skip)]
    updates_applied_so_far: usize,
}

impl Arena {
    pub fn add_player(&mut self, player: Player) {
        self.updates.push(ArenaUpdate::AddPlayer(player.id, player));
    }

    pub fn remove_player(&mut self, player_id: PlayerId) {
        self.updates.push(ArenaUpdate::RemovePlayer(player_id));
    }

    pub fn clear_updates(&mut self) {
        self.updates.clear();
        self.updates_applied_so_far = 0;
    }

    pub fn apply_updates(&mut self) -> &mut Self {
        let updates = mem::replace(&mut self.updates, Vec::new());
        for update in updates.iter().skip(self.updates_applied_so_far) {
            update.apply(self);
            self.updates_applied_so_far += 1;
        }
        mem::replace(&mut self.updates, updates);

        self
    }

    pub fn process_input(&mut self, player_id: PlayerId, input_event: ArenaInput) {
        input_event
            .process_into_updates(self, player_id)
            .drain(..)
            .for_each(|update| self.updates.push(update));
    }

    pub fn update(&mut self) {
        // apply process_input updates
        self.apply_updates();

        let started = match self.started {
            Some(started) => started,
            None => return,
        };

        let now = Utc::now();
        if now < started {
            return;
        }

        self.update_lightcycle_positions()
            .apply_updates()
            .calculate_lightcycle_collisions()
            .apply_updates()
            .update_trail_positions()
            .apply_updates();
    }

    //
    // update helpers
    //

    fn update_lightcycle_positions(&mut self) -> &mut Self {
        for (id, lightcycle) in self.lightcycles.iter() {
            if lightcycle.dead {
                continue;
            };

            self.updates
                .push(ArenaUpdate::UpdateLightcycleApplyVelocity(*id))
        }
        self
    }

    fn calculate_lightcycle_collisions(&mut self) -> &mut Self {
        'next_lightcycle: for (id, lightcycle) in self.lightcycles.iter() {
            if lightcycle.dead {
                continue 'next_lightcycle;
            };

            for trail in self.trails.values() {
                for line in trail.points.windows(2) {
                    let start = line[0];
                    let end = line[1];

                    if is_point_on_line_2d(lightcycle.position, Line(start, end)) {
                        self.updates
                            .push(ArenaUpdate::UpdateLightcycleApplyDeath(*id));
                        continue 'next_lightcycle;
                    }
                }
            }
        }
        self
    }

    fn update_trail_positions(&mut self) -> &mut Self {
        for id in self.trails.keys() {
            let latest_point = match self.lightcycles.get(id) {
                Some(lightcycle) => {
                    if lightcycle.dead {
                        continue;
                    };

                    lightcycle.position
                }
                None => {
                    error!(
                        "Failed to update trail position: No lightcycle with id {}",
                        id
                    );
                    continue;
                }
            };

            self.updates
                .push(ArenaUpdate::UpdateTrailReplaceLatestPoint(
                    *id,
                    latest_point,
                ));
        }
        self
    }
}

impl Default for Arena {
    fn default() -> Self {
        Self {
            id: ArenaId::new_v4(),
            width: ARENA_WIDTH,
            height: ARENA_HEIGHT,
            max_players: ARENA_MAX_PLAYERS,

            started: None,

            players: Default::default(),
            lightcycles: Default::default(),
            trails: Default::default(),

            updates: Default::default(),
            updates_applied_so_far: 0,
        }
    }
}

/// ArenaOverview represents an overview of an Arena for the arena selection screen.
#[derive(Debug, Clone, Serialize)]
pub struct ArenaOverview {
    id: ArenaId,
    max_players: usize,
    started: Option<DateTime<Utc>>,
    players: HashMap<PlayerId, Player>,
}

impl From<&Arena> for ArenaOverview {
    fn from(arena: &Arena) -> Self {
        Self {
            id: arena.id,
            max_players: arena.max_players,
            started: arena.started,
            players: arena.players.clone(),
        }
    }
}
<|endoftext|>


<commit_before>use std::{
    hash::Hash,
    iter::{from_fn, FromIterator},
};

use indexmap::IndexSet;

use crate::{
    visit::{IntoNeighborsDirected, NodeCount},
    Direction::Outgoing,
};

/// Returns iterator that produces all simple paths from `from` node to `to`, which contains at least `min_intermediate_nodes` nodes
/// and at most `max_intermediate_nodes`, if given, limited by graph's order otherwise
/// Simple path is path without repetitions
/// Algorithm is adopted from https://networkx.github.io/documentation/stable/reference/algorithms/generated/networkx.algorithms.simple_paths.all_simple_paths.html
///
/// # Example
/// ```
/// use petgraph::{algo, prelude::*};
///
/// let mut graph = DiGraph::<&str, i32>::new();
///
/// let a = graph.add_node("a");
/// let b = graph.add_node("b");
/// let c = graph.add_node("c");
/// let d = graph.add_node("d");
///
/// graph.extend_with_edges(&[(a, b, 1), (b, c, 1), (c, d, 1), (a, b, 1), (b, d, 1)]);
///
/// let ways = algo::all_simple_paths::<Vec<_>, _>(&graph, a, d, 0, None)
///   .collect::<Vec<_>>();
///
/// assert_eq!(4, ways.len());
/// ```
pub fn all_simple_paths<TargetColl, G>(
    graph: G,
    from: G::NodeId,
    to: G::NodeId,
    min_intermediate_nodes: usize,
    max_intermediate_nodes: Option<usize>,
) -> impl Iterator<Item = TargetColl>
where
    G: NodeCount,
    G: IntoNeighborsDirected,
    G::NodeId: Eq + Hash,
    TargetColl: FromIterator<G::NodeId>,
{
    // how many nodes are allowed in simple path up to target node
    // it is min/max allowed path length minus one, because it is more appropriate when implementing lookahead
    // than constantly add 1 to length of current path
    let max_length = if let Some(l) = max_intermediate_nodes {
        l + 1
    } else {
        graph.node_count() - 1
    };

    let min_length = min_intermediate_nodes + 1;

    // list of visited nodes
    let mut visited: IndexSet<G::NodeId> = IndexSet::from_iter(Some(from));
    // list of childs of currently exploring path nodes,
    // last elem is list of childs of last visited node
    let mut stack = vec![graph.neighbors_directed(from, Outgoing)];

    from_fn(move || {
        while let Some(children) = stack.last_mut() {
            if let Some(child) = children.next() {
                if visited.len() < max_length {
                    if child == to {
                        if visited.len() >= min_length {
                            let path = visited
                                .iter()
                                .cloned()
                                .chain(Some(to))
                                .collect::<TargetColl>();
                            return Some(path);
                        }
                    } else if !visited.contains(&child) {
                        visited.insert(child);
                        stack.push(graph.neighbors_directed(child, Outgoing));
                    }
                } else {
                    if (child == to || children.any(|v| v == to)) && visited.len() >= min_length {
                        let path = visited
                            .iter()
                            .cloned()
                            .chain(Some(to))
                            .collect::<TargetColl>();
                        return Some(path);
                    }
                    stack.pop();
                    visited.pop();
                }
            } else {
                stack.pop();
                visited.pop();
            }
        }
        None
    })
}

#[cfg(test)]
mod test {
    use std::{collections::HashSet, iter::FromIterator};

    use itertools::assert_equal;

    use crate::{dot::Dot, prelude::DiGraph};

    use super::all_simple_paths;

    #[test]
    fn test_all_simple_paths() {
        let graph = DiGraph::<i32, i32, _>::from_edges(&[
            (0, 1),
            (0, 2),
            (0, 3),
            (1, 2),
            (1, 3),
            (2, 3),
            (2, 4),
            (3, 2),
            (3, 4),
            (4, 2),
            (4, 5),
            (5, 2),
            (5, 3),
        ]);

        let expexted_simple_paths_0_to_5 = vec![
            vec![0usize, 1, 2, 3, 4, 5],
            vec![0, 1, 2, 4, 5],
            vec![0, 1, 3, 2, 4, 5],
            vec![0, 1, 3, 4, 5],
            vec![0, 2, 3, 4, 5],
            vec![0, 2, 4, 5],
            vec![0, 3, 2, 4, 5],
            vec![0, 3, 4, 5],
        ];

        println!("{}", Dot::new(&graph));
        let actual_simple_paths_0_to_5: HashSet<Vec<_>> =
            all_simple_paths(&graph, 0u32.into(), 5u32.into(), 0, None)
                .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
                .collect();
        assert_eq!(actual_simple_paths_0_to_5.len(), 8);
        assert_eq!(
            HashSet::from_iter(expexted_simple_paths_0_to_5),
            actual_simple_paths_0_to_5
        );
    }

    #[test]
    fn test_one_simple_path() {
        let graph = DiGraph::<i32, i32, _>::from_edges(&[(0, 1), (2, 1)]);

        let expexted_simple_paths_0_to_1 = &[vec![0usize, 1]];
        println!("{}", Dot::new(&graph));
        let actual_simple_paths_0_to_1: Vec<Vec<_>> =
            all_simple_paths(&graph, 0u32.into(), 1u32.into(), 0, None)
                .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
                .collect();

        assert_eq!(actual_simple_paths_0_to_1.len(), 1);
        assert_equal(expexted_simple_paths_0_to_1, &actual_simple_paths_0_to_1);
    }

    #[test]
    fn test_no_simple_paths() {
        let graph = DiGraph::<i32, i32, _>::from_edges(&[(0, 1), (2, 1)]);

        println!("{}", Dot::new(&graph));
        let actual_simple_paths_0_to_2: Vec<Vec<_>> =
            all_simple_paths(&graph, 0u32.into(), 2u32.into(), 0, None)
                .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
                .collect();

        assert_eq!(actual_simple_paths_0_to_2.len(), 0);
    }
}
<commit_msg>Fix a formatting issue in the algo module's docs (#437)<commit_after>use std::{
    hash::Hash,
    iter::{from_fn, FromIterator},
};

use indexmap::IndexSet;

use crate::{
    visit::{IntoNeighborsDirected, NodeCount},
    Direction::Outgoing,
};

/// Returns an iterator that produces all simple paths from `from` node to `to`, which contains at least `min_intermediate_nodes` nodes
/// and at most `max_intermediate_nodes`, if given, or limited by the graph's order otherwise. The simple path is a path without repetitions.
///
/// This algorithm is adapted from https://networkx.github.io/documentation/stable/reference/algorithms/generated/networkx.algorithms.simple_paths.all_simple_paths.html
///
/// # Example
/// ```
/// use petgraph::{algo, prelude::*};
///
/// let mut graph = DiGraph::<&str, i32>::new();
///
/// let a = graph.add_node("a");
/// let b = graph.add_node("b");
/// let c = graph.add_node("c");
/// let d = graph.add_node("d");
///
/// graph.extend_with_edges(&[(a, b, 1), (b, c, 1), (c, d, 1), (a, b, 1), (b, d, 1)]);
///
/// let ways = algo::all_simple_paths::<Vec<_>, _>(&graph, a, d, 0, None)
///   .collect::<Vec<_>>();
///
/// assert_eq!(4, ways.len());
/// ```
pub fn all_simple_paths<TargetColl, G>(
    graph: G,
    from: G::NodeId,
    to: G::NodeId,
    min_intermediate_nodes: usize,
    max_intermediate_nodes: Option<usize>,
) -> impl Iterator<Item = TargetColl>
where
    G: NodeCount,
    G: IntoNeighborsDirected,
    G::NodeId: Eq + Hash,
    TargetColl: FromIterator<G::NodeId>,
{
    // how many nodes are allowed in simple path up to target node
    // it is min/max allowed path length minus one, because it is more appropriate when implementing lookahead
    // than constantly add 1 to length of current path
    let max_length = if let Some(l) = max_intermediate_nodes {
        l + 1
    } else {
        graph.node_count() - 1
    };

    let min_length = min_intermediate_nodes + 1;

    // list of visited nodes
    let mut visited: IndexSet<G::NodeId> = IndexSet::from_iter(Some(from));
    // list of childs of currently exploring path nodes,
    // last elem is list of childs of last visited node
    let mut stack = vec![graph.neighbors_directed(from, Outgoing)];

    from_fn(move || {
        while let Some(children) = stack.last_mut() {
            if let Some(child) = children.next() {
                if visited.len() < max_length {
                    if child == to {
                        if visited.len() >= min_length {
                            let path = visited
                                .iter()
                                .cloned()
                                .chain(Some(to))
                                .collect::<TargetColl>();
                            return Some(path);
                        }
                    } else if !visited.contains(&child) {
                        visited.insert(child);
                        stack.push(graph.neighbors_directed(child, Outgoing));
                    }
                } else {
                    if (child == to || children.any(|v| v == to)) && visited.len() >= min_length {
                        let path = visited
                            .iter()
                            .cloned()
                            .chain(Some(to))
                            .collect::<TargetColl>();
                        return Some(path);
                    }
                    stack.pop();
                    visited.pop();
                }
            } else {
                stack.pop();
                visited.pop();
            }
        }
        None
    })
}

#[cfg(test)]
mod test {
    use std::{collections::HashSet, iter::FromIterator};

    use itertools::assert_equal;

    use crate::{dot::Dot, prelude::DiGraph};

    use super::all_simple_paths;

    #[test]
    fn test_all_simple_paths() {
        let graph = DiGraph::<i32, i32, _>::from_edges(&[
            (0, 1),
            (0, 2),
            (0, 3),
            (1, 2),
            (1, 3),
            (2, 3),
            (2, 4),
            (3, 2),
            (3, 4),
            (4, 2),
            (4, 5),
            (5, 2),
            (5, 3),
        ]);

        let expexted_simple_paths_0_to_5 = vec![
            vec![0usize, 1, 2, 3, 4, 5],
            vec![0, 1, 2, 4, 5],
            vec![0, 1, 3, 2, 4, 5],
            vec![0, 1, 3, 4, 5],
            vec![0, 2, 3, 4, 5],
            vec![0, 2, 4, 5],
            vec![0, 3, 2, 4, 5],
            vec![0, 3, 4, 5],
        ];

        println!("{}", Dot::new(&graph));
        let actual_simple_paths_0_to_5: HashSet<Vec<_>> =
            all_simple_paths(&graph, 0u32.into(), 5u32.into(), 0, None)
                .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
                .collect();
        assert_eq!(actual_simple_paths_0_to_5.len(), 8);
        assert_eq!(
            HashSet::from_iter(expexted_simple_paths_0_to_5),
            actual_simple_paths_0_to_5
        );
    }

    #[test]
    fn test_one_simple_path() {
        let graph = DiGraph::<i32, i32, _>::from_edges(&[(0, 1), (2, 1)]);

        let expexted_simple_paths_0_to_1 = &[vec![0usize, 1]];
        println!("{}", Dot::new(&graph));
        let actual_simple_paths_0_to_1: Vec<Vec<_>> =
            all_simple_paths(&graph, 0u32.into(), 1u32.into(), 0, None)
                .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
                .collect();

        assert_eq!(actual_simple_paths_0_to_1.len(), 1);
        assert_equal(expexted_simple_paths_0_to_1, &actual_simple_paths_0_to_1);
    }

    #[test]
    fn test_no_simple_paths() {
        let graph = DiGraph::<i32, i32, _>::from_edges(&[(0, 1), (2, 1)]);

        println!("{}", Dot::new(&graph));
        let actual_simple_paths_0_to_2: Vec<Vec<_>> =
            all_simple_paths(&graph, 0u32.into(), 2u32.into(), 0, None)
                .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
                .collect();

        assert_eq!(actual_simple_paths_0_to_2.len(), 0);
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

#[derive(Debug)]
pub enum FileHeaderSpec {
    Null,
    Bool,
    Integer,
    UInteger,
    Float,
    Text,
    Key { name: String, value_type: Box<FileHeaderSpec> },
    Array { allowed_types: Box<Vec<FileHeaderSpec>> },
}

#[derive(Debug)]
pub enum FileHeaderData {
    Null,
    Bool(bool),
    Integer(i64),
    UInteger(u64),
    Float(f64),
    Text(String),
    Key { name: String, value: Box<FileHeaderData> },
    Array { values: Box<Vec<FileHeaderData>> },
}

pub trait FileData : Sized {
    fn get_fulltext(&self) -> String;
    fn get_abbrev(&self) -> String;
}

impl Display for FileHeaderSpec {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match self {
            &FileHeaderSpec::Null       => write!(fmt, "NULL"),
            &FileHeaderSpec::Bool       => write!(fmt, "Bool"),
            &FileHeaderSpec::Integer    => write!(fmt, "Integer"),
            &FileHeaderSpec::UInteger   => write!(fmt, "UInteger"),
            &FileHeaderSpec::Float      => write!(fmt, "Float"),
            &FileHeaderSpec::Text       => write!(fmt, "Text"),
            &FileHeaderSpec::Key{name: ref n, value_type: ref vt} => {
                write!(fmt, "Key({:?}) -> {:?}", n, vt)
            }
            &FileHeaderSpec::Array{allowed_types: ref at}  => {
                write!(fmt, "Array({:?})", at)
            }
        }
    }

}

pub struct MatchError {
    summary: String,
    path: Vec<FileHeaderSpec>,
    expected: FileHeaderSpec,
    found: FileHeaderSpec
}

impl MatchError {
    pub fn format(&self) -> String {
        format!("MatchError: {:?}\n\nHaving: {:?}\nExpected: {:?}\nFound: {:?}\n",
               self.summary, self.path, self.expected, self.found)
    }
}

impl Error for MatchError {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl Debug for MatchError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

impl Display for MatchError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

<commit_msg>Add algorithm to match spec on data<commit_after>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

#[derive(Debug)]
pub enum FileHeaderSpec {
    Null,
    Bool,
    Integer,
    UInteger,
    Float,
    Text,
    Key { name: String, value_type: Box<FileHeaderSpec> },
    Array { allowed_types: Box<Vec<FileHeaderSpec>> },
}

#[derive(Debug)]
pub enum FileHeaderData {
    Null,
    Bool(bool),
    Integer(i64),
    UInteger(u64),
    Float(f64),
    Text(String),
    Key { name: String, value: Box<FileHeaderData> },
    Array { values: Box<Vec<FileHeaderData>> },
}

pub trait FileData : Sized {
    fn get_fulltext(&self) -> String;
    fn get_abbrev(&self) -> String;
}

impl Display for FileHeaderSpec {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match self {
            &FileHeaderSpec::Null       => write!(fmt, "NULL"),
            &FileHeaderSpec::Bool       => write!(fmt, "Bool"),
            &FileHeaderSpec::Integer    => write!(fmt, "Integer"),
            &FileHeaderSpec::UInteger   => write!(fmt, "UInteger"),
            &FileHeaderSpec::Float      => write!(fmt, "Float"),
            &FileHeaderSpec::Text       => write!(fmt, "Text"),
            &FileHeaderSpec::Key{name: ref n, value_type: ref vt} => {
                write!(fmt, "Key({:?}) -> {:?}", n, vt)
            }
            &FileHeaderSpec::Array{allowed_types: ref at}  => {
                write!(fmt, "Array({:?})", at)
            }
        }
    }

}

pub struct MatchError {
    summary: String,
    path: Vec<FileHeaderSpec>,
    expected: FileHeaderSpec,
    found: FileHeaderSpec
}

impl MatchError {
    pub fn format(&self) -> String {
        format!("MatchError: {:?}\n\nHaving: {:?}\nExpected: {:?}\nFound: {:?}\n",
               self.summary, self.path, self.expected, self.found)
    }
}

impl Error for MatchError {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl Debug for MatchError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

impl Display for MatchError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

pub fn match_header_spec(spec: &FileHeaderSpec, data: &FileHeaderData)
    -> Option<MatchError>
{
    let tpl = (spec, data);
    match tpl {
        (&FileHeaderSpec::Null,     &FileHeaderData::Null)           => { }
        (&FileHeaderSpec::Bool,     &FileHeaderData::Bool(_))        => { }
        (&FileHeaderSpec::Integer,  &FileHeaderData::Integer(_))     => { }
        (&FileHeaderSpec::UInteger, &FileHeaderData::UInteger(_))    => { }
        (&FileHeaderSpec::Float,    &FileHeaderData::Float(_))       => { }
        (&FileHeaderSpec::Text,     &FileHeaderData::Text(_))        => { }

        (
            &FileHeaderSpec::Key{name: ref kname, value_type: ref vtype},
            &FileHeaderData::Key{name: ref n, value: ref val}
        ) => {
            if kname != n {
                // error
            }
            return match_header_spec(&*vtype, &*val);
        }

        (
            &FileHeaderSpec::Array{allowed_types: ref vtypes},
            &FileHeaderData::Array{values: ref vs}
        ) => {
            for (t, v) in vtypes.iter().zip(vs.iter()) {
                let res = match_header_spec(t, v);
                if res.is_some() {
                    return res;
                }
            }
        }

        _ => { unreachable!() }
    }
    None
}

<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

pub trait FromLossy<T>: Sized {
    fn from_lossy(_: T) -> Self;
}

pub trait IntoLossy<T>: Sized {
    fn into_lossy(self) -> T;
}

impl<T, U> IntoLossy<U> for T
where
    U: FromLossy<T>,
{

    fn into_lossy(self) -> U {
        U::from_lossy(self)
    }
}
<commit_msg>Add documentation for the conversion module.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Traits for conversions between types.
//!
//! This module provides utility traits similar to what `std::convert` does and
//! can be thought as an extension of it to fit RRG-specific purposes.

/// A lossy conversion from one type to the other.
///
/// This trait is very similar to `From` from the standard library, except that
/// it allows values to lose some information. Moreover, the implementers are
/// allowed to log details about the lost information, so the conversion might
/// have side effects.
///
/// See also [`IntoLossy`].
///
/// [`IntoLossy`]: trait.IntoLossy.html
pub trait FromLossy<T>: Sized {
    /// Convert the value of another type.
    fn from_lossy(_: T) -> Self;
}

/// A lossy conversion into one type from the other.
///
/// This trait is very similar to `Into` from the standard library, except that
/// it allows values to lose some information. Moreover, the implementers are
/// allowed to log details about the lost information, so the conversion might
/// have side effects.
///
/// Note that it is discouraged to implement this trait directly. Instead, one
/// should provide a reverse implementation for [`FromLossy`] and derive the
/// implementation for `IntoLossy` automatically.
///
/// [`FromLossy`]: trait.FromLossy.html
pub trait IntoLossy<T>: Sized {
    /// Convert the value into another type.
    fn into_lossy(self) -> T;
}

impl<T, U> IntoLossy<U> for T
where
    U: FromLossy<T>,
{

    fn into_lossy(self) -> U {
        U::from_lossy(self)
    }
}
<|endoftext|>