<commit_before>use crate::config;

use crate::infer_schema_internals::*;
use serde::de::{self, MapAccess, Visitor};
use serde::{Deserialize, Deserializer};
use std::error::Error;
use std::fmt::{self, Display, Formatter, Write};
use std::io::Write as IoWrite;

const SCHEMA_HEADER: &str = "// @generated automatically by Diesel CLI.\r\n\r\n";

pub enum Filtering {
    OnlyTables(Vec<TableName>),
    ExceptTables(Vec<TableName>),
    None,
}

impl Default for Filtering {
    fn default() -> Self {
        Filtering::None
    }
}

impl Filtering {
    pub fn should_ignore_table(&self, name: &TableName) -> bool {
        use self::Filtering::*;

        match *self {
            OnlyTables(ref names) => !names.contains(name),
            ExceptTables(ref names) => names.contains(name),
            None => false,
        }
    }
}

pub fn run_print_schema<W: IoWrite>(
    database_url: &str,
    config: &config::PrintSchema,
    output: &mut W,
) -> Result<(), Box<dyn Error>> {
    let schema = output_schema(database_url, config)?;

    output.write_all(schema.as_bytes())?;
    Ok(())
}

pub fn output_schema(
    database_url: &str,
    config: &config::PrintSchema,
) -> Result<String, Box<dyn Error>> {
    let table_names = load_table_names(database_url, config.schema_name())?
        .into_iter()
        .filter(|t| !config.filter.should_ignore_table(t))
        .collect::<Vec<_>>();
    let foreign_keys = load_foreign_key_constraints(database_url, config.schema_name())?;
    let foreign_keys =
        remove_unsafe_foreign_keys_for_codegen(database_url, &foreign_keys, &table_names);
    let table_data = table_names
        .into_iter()
        .map(|t| load_table_data(database_url, t))
        .collect::<Result<_, Box<dyn Error>>>()?;
    let definitions = TableDefinitions {
        tables: table_data,
        fk_constraints: foreign_keys,
        include_docs: config.with_docs,
        import_types: config.import_types(),
    };

    let mut out = String::from(SCHEMA_HEADER);

    if let Some(schema_name) = config.schema_name() {
        write!(out, "{}", ModuleDefinition(schema_name, definitions))?;
    } else {
        write!(out, "{}", definitions)?;
    }

    if let Some(ref patch_file) = config.patch_file {
        let patch = std::fs::read_to_string(patch_file)?;
        let patch = diffy::Patch::from_str(&patch)?;

        out = diffy::apply(&out, &patch)?;
    }

    Ok(out)
}

struct ModuleDefinition<'a>(&'a str, TableDefinitions<'a>);

impl<'a> Display for ModuleDefinition<'a> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        {
            let mut out = PadAdapter::new(f);
            writeln!(out, "pub mod {} {{", self.0)?;
            write!(out, "{}", self.1)?;
        }
        writeln!(f, "}}")?;
        Ok(())
    }
}

struct TableDefinitions<'a> {
    tables: Vec<TableData>,
    fk_constraints: Vec<ForeignKeyConstraint>,
    include_docs: bool,
    import_types: Option<&'a [String]>,
}

impl<'a> Display for TableDefinitions<'a> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let mut is_first = true;
        for table in &self.tables {
            if is_first {
                is_first = false;
            } else {
                writeln!(f)?;
            }
            writeln!(
                f,
                "{}",
                TableDefinition {
                    table,
                    include_docs: self.include_docs,
                    import_types: self.import_types,
                }
            )?;
        }

        if !self.fk_constraints.is_empty() {
            writeln!(f)?;
        }

        for foreign_key in &self.fk_constraints {
            writeln!(f, "{}", Joinable(foreign_key))?;
        }

        if self.tables.len() > 1 {
            write!(f, "\ndiesel::allow_tables_to_appear_in_same_query!(")?;
            {
                let mut out = PadAdapter::new(f);
                writeln!(out)?;
                for table in &self.tables {
                    if table.name.rust_name == table.name.sql_name {
                        writeln!(out, "{},", table.name.sql_name)?;
                    } else {
                        writeln!(out, "{},", table.name.rust_name)?;
                    }
                }
            }
            writeln!(f, ");")?;
        }

        Ok(())
    }
}

struct TableDefinition<'a> {
    table: &'a TableData,
    import_types: Option<&'a [String]>,
    include_docs: bool,
}

impl<'a> Display for TableDefinition<'a> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "diesel::table! {{")?;
        {
            let mut out = PadAdapter::new(f);
            writeln!(out)?;

            if let Some(types) = self.import_types {
                for import in types {
                    writeln!(out, "use {};", import)?;
                }
                writeln!(out)?;
            }

            if self.include_docs {
                for d in self.table.docs.lines() {
                    writeln!(out, "///{}{}", if d.is_empty() { "" } else { " " }, d)?;
                }
            }

            if self.table.name.rust_name != self.table.name.sql_name {
                writeln!(
                    out,
                    r#"#[sql_name = "{}"]"#,
                    self.table.name.full_sql_name()
                )?;
            }

            write!(out, "{} (", self.table.name)?;

            for (i, pk) in self.table.primary_key.iter().enumerate() {
                if i != 0 {
                    write!(out, ", ")?;
                }
                write!(out, "{}", pk)?;
            }

            write!(
                out,
                ") {}",
                ColumnDefinitions {
                    columns: &self.table.column_data,
                    include_docs: self.include_docs,
                }
            )?;
        }
        write!(f, "}}")?;
        Ok(())
    }
}

struct ColumnDefinitions<'a> {
    columns: &'a [ColumnDefinition],
    include_docs: bool,
}

impl<'a> Display for ColumnDefinitions<'a> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        {
            let mut out = PadAdapter::new(f);
            writeln!(out, "{{")?;
            for column in self.columns {
                if self.include_docs {
                    for d in column.docs.lines() {
                        writeln!(out, "///{}{}", if d.is_empty() { "" } else { " " }, d)?;
                    }
                }
                if column.rust_name == column.sql_name {
                    writeln!(out, "{} -> {},", column.sql_name, column.ty)?;
                } else {
                    writeln!(out, r#"#[sql_name = "{}"]"#, column.sql_name)?;
                    writeln!(out, "{} -> {},", column.rust_name, column.ty)?;
                }
            }
        }
        writeln!(f, "}}")?;
        Ok(())
    }
}

struct Joinable<'a>(&'a ForeignKeyConstraint);

impl<'a> Display for Joinable<'a> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let child_table_name = &self.0.child_table.rust_name;

        let parent_table_name = &self.0.parent_table.rust_name;

        write!(
            f,
            "diesel::joinable!({} -> {} ({}));",
            child_table_name, parent_table_name, self.0.foreign_key_rust_name,
        )
    }
}

/// Lifted directly from libcore/fmt/builders.rs
struct PadAdapter<'a, 'b: 'a> {
    fmt: &'a mut Formatter<'b>,
    on_newline: bool,
}

impl<'a, 'b: 'a> PadAdapter<'a, 'b> {
    fn new(fmt: &'a mut Formatter<'b>) -> PadAdapter<'a, 'b> {
        PadAdapter {
            fmt,
            on_newline: false,
        }
    }
}

impl<'a, 'b: 'a> Write for PadAdapter<'a, 'b> {
    fn write_str(&mut self, mut s: &str) -> fmt::Result {
        while !s.is_empty() {
            let on_newline = self.on_newline;

            let split = match s.find('\n') {
                Some(pos) => {
                    self.on_newline = true;
                    pos + 1
                }
                None => {
                    self.on_newline = false;
                    s.len()
                }
            };

            let to_write = &s[..split];
            if on_newline && to_write != "\n" {
                self.fmt.write_str("    ")?;
            }
            self.fmt.write_str(to_write)?;

            s = &s[split..];
        }

        Ok(())
    }
}

impl<'de> Deserialize<'de> for Filtering {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct FilteringVisitor;

        impl<'de> Visitor<'de> for FilteringVisitor {
            type Value = Filtering;

            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
                f.write_str("either only_tables or except_tables")
            }

            fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
            where
                V: MapAccess<'de>,
            {
                let mut only_tables = None;
                let mut except_tables = None;
                while let Some((key, value)) = map.next_entry()? {
                    match key {
                        "only_tables" => {
                            if only_tables.is_some() {
                                return Err(de::Error::duplicate_field("only_tables"));
                            }
                            only_tables = Some(value);
                        }
                        "except_tables" => {
                            if except_tables.is_some() {
                                return Err(de::Error::duplicate_field("except_tables"));
                            }
                            except_tables = Some(value);
                        }
                        _ => {
                            return Err(de::Error::unknown_field(
                                key,
                                &["only_tables", "except_tables"],
                            ))
                        }
                    }
                }
                match (only_tables, except_tables) {
                    (Some(_), Some(_)) => Err(de::Error::duplicate_field("except_tables")),
                    (Some(w), None) => Ok(Filtering::OnlyTables(w)),
                    (None, Some(b)) => Ok(Filtering::ExceptTables(b)),
                    (None, None) => Ok(Filtering::None),
                }
            }
        }

        deserializer.deserialize_map(FilteringVisitor)
    }
}
<commit_msg>fix: remove carriage return char<commit_after>use crate::config;

use crate::infer_schema_internals::*;
use serde::de::{self, MapAccess, Visitor};
use serde::{Deserialize, Deserializer};
use std::error::Error;
use std::fmt::{self, Display, Formatter, Write};
use std::io::Write as IoWrite;

const SCHEMA_HEADER: &str = "// @generated automatically by Diesel CLI.\n";

pub enum Filtering {
    OnlyTables(Vec<TableName>),
    ExceptTables(Vec<TableName>),
    None,
}

impl Default for Filtering {
    fn default() -> Self {
        Filtering::None
    }
}

impl Filtering {
    pub fn should_ignore_table(&self, name: &TableName) -> bool {
        use self::Filtering::*;

        match *self {
            OnlyTables(ref names) => !names.contains(name),
            ExceptTables(ref names) => names.contains(name),
            None => false,
        }
    }
}

pub fn run_print_schema<W: IoWrite>(
    database_url: &str,
    config: &config::PrintSchema,
    output: &mut W,
) -> Result<(), Box<dyn Error>> {
    let schema = output_schema(database_url, config)?;

    output.write_all(schema.as_bytes())?;
    Ok(())
}

pub fn output_schema(
    database_url: &str,
    config: &config::PrintSchema,
) -> Result<String, Box<dyn Error>> {
    let table_names = load_table_names(database_url, config.schema_name())?
        .into_iter()
        .filter(|t| !config.filter.should_ignore_table(t))
        .collect::<Vec<_>>();
    let foreign_keys = load_foreign_key_constraints(database_url, config.schema_name())?;
    let foreign_keys =
        remove_unsafe_foreign_keys_for_codegen(database_url, &foreign_keys, &table_names);
    let table_data = table_names
        .into_iter()
        .map(|t| load_table_data(database_url, t))
        .collect::<Result<_, Box<dyn Error>>>()?;
    let definitions = TableDefinitions {
        tables: table_data,
        fk_constraints: foreign_keys,
        include_docs: config.with_docs,
        import_types: config.import_types(),
    };

    let mut out = String::new();
    writeln!(out, "{}", SCHEMA_HEADER)?;

    if let Some(schema_name) = config.schema_name() {
        write!(out, "{}", ModuleDefinition(schema_name, definitions))?;
    } else {
        write!(out, "{}", definitions)?;
    }

    if let Some(ref patch_file) = config.patch_file {
        let patch = std::fs::read_to_string(patch_file)?;
        let patch = diffy::Patch::from_str(&patch)?;

        out = diffy::apply(&out, &patch)?;
    }

    Ok(out)
}

struct ModuleDefinition<'a>(&'a str, TableDefinitions<'a>);

impl<'a> Display for ModuleDefinition<'a> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        {
            let mut out = PadAdapter::new(f);
            writeln!(out, "pub mod {} {{", self.0)?;
            write!(out, "{}", self.1)?;
        }
        writeln!(f, "}}")?;
        Ok(())
    }
}

struct TableDefinitions<'a> {
    tables: Vec<TableData>,
    fk_constraints: Vec<ForeignKeyConstraint>,
    include_docs: bool,
    import_types: Option<&'a [String]>,
}

impl<'a> Display for TableDefinitions<'a> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let mut is_first = true;
        for table in &self.tables {
            if is_first {
                is_first = false;
            } else {
                writeln!(f)?;
            }
            writeln!(
                f,
                "{}",
                TableDefinition {
                    table,
                    include_docs: self.include_docs,
                    import_types: self.import_types,
                }
            )?;
        }

        if !self.fk_constraints.is_empty() {
            writeln!(f)?;
        }

        for foreign_key in &self.fk_constraints {
            writeln!(f, "{}", Joinable(foreign_key))?;
        }

        if self.tables.len() > 1 {
            write!(f, "\ndiesel::allow_tables_to_appear_in_same_query!(")?;
            {
                let mut out = PadAdapter::new(f);
                writeln!(out)?;
                for table in &self.tables {
                    if table.name.rust_name == table.name.sql_name {
                        writeln!(out, "{},", table.name.sql_name)?;
                    } else {
                        writeln!(out, "{},", table.name.rust_name)?;
                    }
                }
            }
            writeln!(f, ");")?;
        }

        Ok(())
    }
}

struct TableDefinition<'a> {
    table: &'a TableData,
    import_types: Option<&'a [String]>,
    include_docs: bool,
}

impl<'a> Display for TableDefinition<'a> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "diesel::table! {{")?;
        {
            let mut out = PadAdapter::new(f);
            writeln!(out)?;

            if let Some(types) = self.import_types {
                for import in types {
                    writeln!(out, "use {};", import)?;
                }
                writeln!(out)?;
            }

            if self.include_docs {
                for d in self.table.docs.lines() {
                    writeln!(out, "///{}{}", if d.is_empty() { "" } else { " " }, d)?;
                }
            }

            if self.table.name.rust_name != self.table.name.sql_name {
                writeln!(
                    out,
                    r#"#[sql_name = "{}"]"#,
                    self.table.name.full_sql_name()
                )?;
            }

            write!(out, "{} (", self.table.name)?;

            for (i, pk) in self.table.primary_key.iter().enumerate() {
                if i != 0 {
                    write!(out, ", ")?;
                }
                write!(out, "{}", pk)?;
            }

            write!(
                out,
                ") {}",
                ColumnDefinitions {
                    columns: &self.table.column_data,
                    include_docs: self.include_docs,
                }
            )?;
        }
        write!(f, "}}")?;
        Ok(())
    }
}

struct ColumnDefinitions<'a> {
    columns: &'a [ColumnDefinition],
    include_docs: bool,
}

impl<'a> Display for ColumnDefinitions<'a> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        {
            let mut out = PadAdapter::new(f);
            writeln!(out, "{{")?;
            for column in self.columns {
                if self.include_docs {
                    for d in column.docs.lines() {
                        writeln!(out, "///{}{}", if d.is_empty() { "" } else { " " }, d)?;
                    }
                }
                if column.rust_name == column.sql_name {
                    writeln!(out, "{} -> {},", column.sql_name, column.ty)?;
                } else {
                    writeln!(out, r#"#[sql_name = "{}"]"#, column.sql_name)?;
                    writeln!(out, "{} -> {},", column.rust_name, column.ty)?;
                }
            }
        }
        writeln!(f, "}}")?;
        Ok(())
    }
}

struct Joinable<'a>(&'a ForeignKeyConstraint);

impl<'a> Display for Joinable<'a> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let child_table_name = &self.0.child_table.rust_name;

        let parent_table_name = &self.0.parent_table.rust_name;

        write!(
            f,
            "diesel::joinable!({} -> {} ({}));",
            child_table_name, parent_table_name, self.0.foreign_key_rust_name,
        )
    }
}

/// Lifted directly from libcore/fmt/builders.rs
struct PadAdapter<'a, 'b: 'a> {
    fmt: &'a mut Formatter<'b>,
    on_newline: bool,
}

impl<'a, 'b: 'a> PadAdapter<'a, 'b> {
    fn new(fmt: &'a mut Formatter<'b>) -> PadAdapter<'a, 'b> {
        PadAdapter {
            fmt,
            on_newline: false,
        }
    }
}

impl<'a, 'b: 'a> Write for PadAdapter<'a, 'b> {
    fn write_str(&mut self, mut s: &str) -> fmt::Result {
        while !s.is_empty() {
            let on_newline = self.on_newline;

            let split = match s.find('\n') {
                Some(pos) => {
                    self.on_newline = true;
                    pos + 1
                }
                None => {
                    self.on_newline = false;
                    s.len()
                }
            };

            let to_write = &s[..split];
            if on_newline && to_write != "\n" {
                self.fmt.write_str("    ")?;
            }
            self.fmt.write_str(to_write)?;

            s = &s[split..];
        }

        Ok(())
    }
}

impl<'de> Deserialize<'de> for Filtering {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct FilteringVisitor;

        impl<'de> Visitor<'de> for FilteringVisitor {
            type Value = Filtering;

            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
                f.write_str("either only_tables or except_tables")
            }

            fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
            where
                V: MapAccess<'de>,
            {
                let mut only_tables = None;
                let mut except_tables = None;
                while let Some((key, value)) = map.next_entry()? {
                    match key {
                        "only_tables" => {
                            if only_tables.is_some() {
                                return Err(de::Error::duplicate_field("only_tables"));
                            }
                            only_tables = Some(value);
                        }
                        "except_tables" => {
                            if except_tables.is_some() {
                                return Err(de::Error::duplicate_field("except_tables"));
                            }
                            except_tables = Some(value);
                        }
                        _ => {
                            return Err(de::Error::unknown_field(
                                key,
                                &["only_tables", "except_tables"],
                            ))
                        }
                    }
                }
                match (only_tables, except_tables) {
                    (Some(_), Some(_)) => Err(de::Error::duplicate_field("except_tables")),
                    (Some(w), None) => Ok(Filtering::OnlyTables(w)),
                    (None, Some(b)) => Ok(Filtering::ExceptTables(b)),
                    (None, None) => Ok(Filtering::None),
                }
            }
        }

        deserializer.deserialize_map(FilteringVisitor)
    }
}
<|endoftext|>


<commit_before>use serde_json::Value;
use ::{Error, Result};
use ::odata::Parameters;

/// Item path
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Path {
	/// The Home folder
	Home,
	/// The Parent favorite item
	Favorites,
	/// The Parent Shared Folders items
	AllShared,
	/// The Parent Connectors item
	Connectors,
	/// The FileBox item
	Box,
	/// The Top item
	Top,
	/// The item identified by ID
	Id(String),
	/// The absolute path
	Absolute(String),
	/// The relative path
	Relative(String, String),
	/// Parent
	Parent(String),
}

impl Path {
	/// Get Item ID if the Path is Id or empty string otherwise.
	pub fn id(&self) -> String {
		match self {
			&Path::Id(ref id) => id.clone(),
			_ => String::new()
		}
	}

	/// Test if path points to the home folder
	pub fn is_home(&self) -> bool {
		match self {
			&Path::Home => true,
			_ => false
		}
	}

	/// Test if path points to the favorites folder
	pub fn is_favorites(&self) -> bool {
		match self {
			&Path::Favorites => true,
			_ => false
		}
	}

	/// Test if path points to the all shared folder
	pub fn is_allshared(&self) -> bool {
		match self {
			&Path::AllShared => true,
			_ => false
		}
	}

	/// Test if path points to the connectors folder
	pub fn is_connectors(&self) -> bool {
		match self {
			&Path::Connectors => true,
			_ => false
		}
	}

	/// Test if path points to the filebox folder
	pub fn is_box(&self) -> bool {
		match self {
			&Path::Box => true,
			_ => false
		}
	}

	/// Test if path points to the top folder
	pub fn is_top(&self) -> bool {
		match self {
			&Path::Top => true,
			_ => false
		}
	}

	/// Test if path holds the ID
	pub fn is_id(&self) -> bool {
		match self {
			&Path::Id(_) => true,
			_ => false
		}
	}

	/// Test if path is absolute
	pub fn is_absolute(&self) -> bool {
		match self {
			&Path::Absolute(_) => true,
			_ => false
		}
	}

	/// Test if path is relative
	pub fn is_relative(&self) -> bool {
		match self {
			&Path::Relative(_, _) => true,
			_ => false
		}
	}

	/// Test if path points to the parent item
	pub fn is_parent(&self) -> bool {
		match self {
			&Path::Parent(_) => true,
			_ => false
		}
	}

	/// Used internally to build OAuth URIs.
	pub fn entity_and_parameters(&self, segment: Option<&str>, parameters: Option<Parameters>) -> String {
		let segment = segment.map_or("", |s| s);
		let parameters = parameters.map_or(String::from(""), |p| p.to_string());

		match self {
			&Path::Home => format!("Items(home){}?{}", segment, parameters),
			&Path::Favorites => format!("Items(favorites){}?{}", segment, parameters),
			&Path::AllShared => format!("Items(allshared){}?{}", segment, parameters),
			&Path::Connectors => format!("Items(connectors){}?{}", segment, parameters),
			&Path::Box => format!("Items(box){}?{}", segment, parameters),
			&Path::Top => format!("Items(top){}?{}", segment, parameters),
			&Path::Id(ref id) => format!("Items({}){}?{}", id, segment, parameters),
			&Path::Absolute(ref path) => format!("Items/ByPath?path={}&{}", path, parameters),
			&Path::Relative(ref id, ref path) => format!("Items({})/ByPath?path={}&{}", id, path, parameters),
			&Path::Parent(ref id) => format!("Items({})/Parent&{}", id, parameters),
		}
	}

	// Parse the path from the result JSON
	pub fn from_json(value: Value) -> Result<Path> {
		value.find("Id")
			.ok_or(Error::new("Cannot find Item ID"))
			.map(|id| Path::Id(id.as_string().unwrap().to_owned()))
	}
}

#[cfg(test)]
mod tests {
	use super::Path;
	use serde_json::{self, Value};

	#[test]
	fn path_home() {
		let path = Path::Home;
		assert!(path.is_home());
	}

	#[test]
	fn path_favorites() {
		let path = Path::Favorites;
		assert!(path.is_favorites());
	}

	#[test]
	fn path_allshared() {
		let path = Path::AllShared;
		assert!(path.is_allshared());
	}

	#[test]
	fn path_connectors() {
		let path = Path::Connectors;
		assert!(path.is_connectors());
	}

	#[test]
	fn path_box() {
		let path = Path::Box;
		assert!(path.is_box());
	}

	#[test]
	fn path_top() {
		let path = Path::Top;
		assert!(path.is_top());
	}

	#[test]
	fn path_id() {
		let path = Path::Id("id".to_owned());
		assert!(path.is_id());
	}

	#[test]
	fn path_absolute() {
		let path = Path::Absolute("path".to_owned());
		assert!(path.is_absolute());
	}

	#[test]
	fn path_relative() {
		let path = Path::Relative("this".to_owned(), "that".to_owned());
		assert!(path.is_relative());
	}

	#[test]
	fn path_parent() {
		let path = Path::Parent("up".to_owned());
		assert!(path.is_parent());
	}

	#[test]
	fn parse_valid_path() {
		let data: Value = serde_json::from_str("{\"Id\":\"fi111111-2222-3333-4444-555555555555\"}").unwrap();
		let path = Path::from_json(data).unwrap();
		assert!(path.is_id());
	}

	#[test]
	#[should_panic]
	fn parse_invalid_path() {
		let data: Value = serde_json::from_str("{\"code\":\"error\"}").unwrap();
		let _ = Path::from_json(data).unwrap();
	}

	#[test]
	fn parse_path_id() {
		let data: Value = serde_json::from_str("{\"Id\":\"fi111111-2222-3333-4444-555555555555\"}").unwrap();
		match Path::from_json(data).unwrap() {
			Path::Id(id) => assert_eq!(id, "fi111111-2222-3333-4444-555555555555"),
			_ => panic!("Parsed Path must be Id")
		};
	}
}
<commit_msg>Add more tests<commit_after>use serde_json::Value;
use ::{Error, Result};
use ::odata::Parameters;

/// Item path
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Path {
	/// The Home folder
	Home,
	/// The Parent favorite item
	Favorites,
	/// The Parent Shared Folders items
	AllShared,
	/// The Parent Connectors item
	Connectors,
	/// The FileBox item
	Box,
	/// The Top item
	Top,
	/// The item identified by ID
	Id(String),
	/// The absolute path
	Absolute(String),
	/// The relative path
	Relative(String, String),
	/// Parent
	Parent(String),
}

impl Path {
	/// Get Item ID if the Path is Id or empty string otherwise.
	pub fn id(&self) -> String {
		match self {
			&Path::Id(ref id) => id.clone(),
			_ => String::new()
		}
	}

	/// Test if path points to the home folder
	pub fn is_home(&self) -> bool {
		match self {
			&Path::Home => true,
			_ => false
		}
	}

	/// Test if path points to the favorites folder
	pub fn is_favorites(&self) -> bool {
		match self {
			&Path::Favorites => true,
			_ => false
		}
	}

	/// Test if path points to the all shared folder
	pub fn is_allshared(&self) -> bool {
		match self {
			&Path::AllShared => true,
			_ => false
		}
	}

	/// Test if path points to the connectors folder
	pub fn is_connectors(&self) -> bool {
		match self {
			&Path::Connectors => true,
			_ => false
		}
	}

	/// Test if path points to the filebox folder
	pub fn is_box(&self) -> bool {
		match self {
			&Path::Box => true,
			_ => false
		}
	}

	/// Test if path points to the top folder
	pub fn is_top(&self) -> bool {
		match self {
			&Path::Top => true,
			_ => false
		}
	}

	/// Test if path holds the ID
	pub fn is_id(&self) -> bool {
		match self {
			&Path::Id(_) => true,
			_ => false
		}
	}

	/// Test if path is absolute
	pub fn is_absolute(&self) -> bool {
		match self {
			&Path::Absolute(_) => true,
			_ => false
		}
	}

	/// Test if path is relative
	pub fn is_relative(&self) -> bool {
		match self {
			&Path::Relative(_, _) => true,
			_ => false
		}
	}

	/// Test if path points to the parent item
	pub fn is_parent(&self) -> bool {
		match self {
			&Path::Parent(_) => true,
			_ => false
		}
	}

	/// Used internally to build OAuth URIs.
	pub fn entity_and_parameters(&self, segment: Option<&str>, parameters: Option<Parameters>) -> String {
		let segment = segment.map_or("", |s| s);
		let parameters = parameters.map_or(String::from(""), |p| p.to_string());

		match self {
			&Path::Home => format!("Items(home){}?{}", segment, parameters),
			&Path::Favorites => format!("Items(favorites){}?{}", segment, parameters),
			&Path::AllShared => format!("Items(allshared){}?{}", segment, parameters),
			&Path::Connectors => format!("Items(connectors){}?{}", segment, parameters),
			&Path::Box => format!("Items(box){}?{}", segment, parameters),
			&Path::Top => format!("Items(top){}?{}", segment, parameters),
			&Path::Id(ref id) => format!("Items({}){}?{}", id, segment, parameters),
			&Path::Absolute(ref path) => format!("Items/ByPath?path={}&{}", path, parameters),
			&Path::Relative(ref id, ref path) => format!("Items({})/ByPath?path={}&{}", id, path, parameters),
			&Path::Parent(ref id) => format!("Items({})/Parent&{}", id, parameters),
		}
	}

	// Parse the path from the result JSON
	pub fn from_json(value: Value) -> Result<Path> {
		value.find("Id")
			.ok_or(Error::new("Cannot find Item ID"))
			.map(|id| Path::Id(id.as_string().unwrap().to_owned()))
	}
}

#[cfg(test)]
mod tests {
	use super::Path;
	use serde_json::{self, Value};

	#[test]
	fn path_get_valid_id() {
		let path = Path::Id(String::from("123"));
		assert_eq!(path.id(), String::from("123"));
	}

	#[test]
	fn path_get_invalid_id() {
		let path = Path::Home;
		assert_eq!(path.id(), String::new());
	}

	#[test]
	fn path_home() {
		let path = Path::Home;
		assert!(path.is_home());
	}

	#[test]
	fn path_favorites() {
		let path = Path::Favorites;
		assert!(path.is_favorites());
	}

	#[test]
	fn path_allshared() {
		let path = Path::AllShared;
		assert!(path.is_allshared());
	}

	#[test]
	fn path_connectors() {
		let path = Path::Connectors;
		assert!(path.is_connectors());
	}

	#[test]
	fn path_box() {
		let path = Path::Box;
		assert!(path.is_box());
	}

	#[test]
	fn path_top() {
		let path = Path::Top;
		assert!(path.is_top());
	}

	#[test]
	fn path_id() {
		let path = Path::Id("id".to_owned());
		assert!(path.is_id());
	}

	#[test]
	fn path_absolute() {
		let path = Path::Absolute("path".to_owned());
		assert!(path.is_absolute());
	}

	#[test]
	fn path_relative() {
		let path = Path::Relative("this".to_owned(), "that".to_owned());
		assert!(path.is_relative());
	}

	#[test]
	fn path_parent() {
		let path = Path::Parent("up".to_owned());
		assert!(path.is_parent());
	}

	#[test]
	fn parse_valid_path() {
		let data: Value = serde_json::from_str("{\"Id\":\"fi111111-2222-3333-4444-555555555555\"}").unwrap();
		let path = Path::from_json(data).unwrap();
		assert!(path.is_id());
	}

	#[test]
	#[should_panic]
	fn parse_invalid_path() {
		let data: Value = serde_json::from_str("{\"code\":\"error\"}").unwrap();
		let _ = Path::from_json(data).unwrap();
	}

	#[test]
	fn parse_path_id() {
		let data: Value = serde_json::from_str("{\"Id\":\"fi111111-2222-3333-4444-555555555555\"}").unwrap();
		match Path::from_json(data).unwrap() {
			Path::Id(id) => assert_eq!(id, "fi111111-2222-3333-4444-555555555555"),
			_ => panic!("Parsed Path must be Id")
		};
	}
}
<|endoftext|>


<commit_before>use bins::error::*;
use bins::Bins;
use bins::configuration::BinsConfiguration;
use bins::engines;
use bins::FlexibleRange;
use bins::network;
use clap::{App, Arg};
use hyper::Url;
use std::path::Path;
use std::process;

pub struct Arguments {
  pub all: bool,
  pub auth: bool,
  pub copy: bool,
  pub files: Vec<String>,
  pub force: bool,
  pub input: Option<String>,
  pub json: bool,
  pub message: Option<String>,
  pub name: Option<String>,
  pub number_lines: bool,
  pub output: Option<String>,
  pub private: bool,
  pub range: Option<FlexibleRange>,
  pub raw_urls: bool,
  pub server: Option<Url>,
  pub service: Option<String>,
  pub urls: bool,
  pub write: bool
}

include!(concat!(env!("OUT_DIR"), "/git_short_tag.rs"));

fn get_name() -> String {
  option_env!("CARGO_PKG_NAME").unwrap_or("unknown_name").to_owned()
}

fn get_version() -> String {
  let version = option_env!("CARGO_PKG_VERSION").unwrap_or("unknown_version").to_owned();
  let git_tag = git_short_tag();
  format!("{}{}", version, git_tag)
}

cfg_if! {
  if #[cfg(feature = "clipboard_support")] {
    fn get_clipboard_args<'a, 'b>() -> Vec<Arg<'a, 'b>> {
      vec![Arg::with_name("copy")
             .short("C")
             .long("copy")
             .help("copies the output of the command to the clipboard without a newline")
             .conflicts_with("no-copy"),
           Arg::with_name("no-copy")
             .short("c")
             .long("no-copy")
             .help("does not copy the output of the command to the clipboard")]
    }
  } else {
    fn get_clipboard_args<'a, 'b>() -> Vec<Arg<'a, 'b>> {
      Vec::new()
    }
  }
}

pub fn get_arguments(config: &BinsConfiguration) -> Result<Arguments> {
  let mut arguments = Arguments {
    all: false,
    auth: config.get_defaults_auth(),
    copy: config.get_defaults_copy(),
    files: Vec::new(),
    force: false,
    input: None,
    json: false,
    message: None,
    name: None,
    number_lines: false,
    output: None,
    private: config.get_defaults_private(),
    range: None,
    raw_urls: false,
    server: None,
    service: config.get_defaults_service().map(|s| s.to_owned()),
    urls: false,
    write: false
  };
  let name = get_name();
  let version = get_version();
  let mut app = App::new(name.as_ref())
    .version(version.as_ref())
    .about("A tool for pasting from the terminal")
    .arg(Arg::with_name("files")
      .help("files to paste")
      .takes_value(true)
      .multiple(true))
    .arg(Arg::with_name("message")
      .short("m")
      .long("message")
      .help("message to paste")
      .use_delimiter(false)
      .takes_value(true)
      .value_name("string"))
    .arg(Arg::with_name("private")
      .short("p")
      .long("private")
      .help("if the paste should be private")
      .conflicts_with("public"))
    .arg(Arg::with_name("public")
      .short("P")
      .long("public")
      .help("if the paste should be public"))
    .arg(Arg::with_name("auth")
      .short("a")
      .long("auth")
      .help("if authentication (like api keys and tokens) should be used")
      .conflicts_with("anon"))
    .arg(Arg::with_name("anon")
      .short("A")
      .long("anon")
      .help("if pastes should be posted without authentication"))
    .arg(Arg::with_name("service")
      .short("s")
      .long("service")
      .help("pastebin service to use")
      .takes_value(true)
      .possible_values(&*engines::get_bin_names())
      .required(arguments.service.is_none()))
    .arg(Arg::with_name("list-services")
      .short("l")
      .long("list-services")
      .help("lists available bins and exits")
      .conflicts_with_all(&["files", "message", "private", "public", "auth", "anon", "service", "input"]))
    .arg(Arg::with_name("input")
      .short("i")
      .long("input")
      .help("displays raw contents of input paste")
      .takes_value(true)
      .value_name("url")
      .conflicts_with_all(&["auth", "anon", "public", "private", "message", "service"]))
    .arg(Arg::with_name("range")
      .short("n")
      .long("range")
      .help("chooses the files to get in input mode, starting from 0 (e.g. \"0\", \"0,1\", \"0-2\", \"2-0,3\")")
      .takes_value(true)
      .value_name("range")
      .use_delimiter(false)
      .requires("input")
      .conflicts_with("files"))
    .arg(Arg::with_name("all")
      .short("L")
      .long("all")
      .help("gets all files in input mode")
      .requires("input")
      .conflicts_with_all(&["files", "range"]))
    .arg(Arg::with_name("raw-urls")
      .short("r")
      .long("raw-urls")
      .help("gets the raw urls instead of the content in input mode")
      .requires("input"))
    .arg(Arg::with_name("urls")
      .short("u")
      .long("urls")
      .help("gets the urls instead of the content in input mode")
      .requires("input")
      .conflicts_with("raw-urls"))
    .arg(Arg::with_name("server")
      .short("S")
      .long("server")
      .help("specifies the server to use for the service (only support on hastebin)")
      .takes_value(true)
      .value_name("server_url"))
    .arg(Arg::with_name("name")
      .short("N")
      .long("name")
      .help("specifies a file name for --message or stdin")
      .takes_value(true)
      .value_name("name")
      .conflicts_with("files"))
    .arg(Arg::with_name("force")
      .short("f")
      .long("force")
      .help("overrides warnings about file type or size when uploading")
      .conflicts_with("input"))
    .arg(Arg::with_name("number_lines")
      .short("e")
      .long("number-lines")
      .help("display line numbers for each file in input mode")
      .requires("input"))
    .arg(Arg::with_name("write")
      .short("w")
      .long("write")
      .help("writes pastes to files in input mode")
      .requires("input"))
    .arg(Arg::with_name("output")
      .short("o")
      .long("output")
      .help("specifies where to save files in write mode")
      .takes_value(true)
      .value_name("dir")
      .requires("write"))
    .arg(Arg::with_name("json")
      .short("j")
      .long("json")
      .help("output json about the paste instead of the contents in input mode"));
  for arg in get_clipboard_args() {
    app = app.arg(arg);
  }
  let res = app.get_matches();
  if res.is_present("list-services") {
    println!("{}", engines::get_bin_names().join("\n"));
    process::exit(0);
  }
  if let Some(files) = res.values_of("files") {
    arguments.files = files.map(|s| s.to_owned()).collect();
  }
  if let Some(message) = res.value_of("message") {
    arguments.message = Some(message.to_owned());
  }
  if let Some(service) = res.value_of("service") {
    arguments.service = Some(service.to_owned());
  }
  if let Some(input) = res.value_of("input") {
    arguments.input = Some(input.to_owned());
  }
  if let Some(range) = res.value_of("range") {
    arguments.range = Some(try!(FlexibleRange::parse(range)));
  }
  if let Some(server) = res.value_of("server") {
    if let Some(ref service) = arguments.service {
      if service.to_lowercase() != "hastebin" {
        return Err("--server may only be used if --service is hastebin".into());
      }
    }
    arguments.server = Some(try!(network::parse_url(server).chain_err(|| "invalid --server")));
  }
  if let Some(name) = res.value_of("name") {
    let name = try!(Bins::sanitize_path(Path::new(name)));
    arguments.name = Some(name.to_owned());
  }
  if let Some(output) = res.value_of("output") {
    arguments.output = Some(output.to_owned());
  }
  arguments.all = res.is_present("all");
  arguments.force = res.is_present("force");
  arguments.json = res.is_present("json");
  arguments.number_lines = res.is_present("number_lines");
  arguments.raw_urls = res.is_present("raw-urls");
  arguments.urls = res.is_present("urls");
  arguments.write = res.is_present("write");
  if res.is_present("private") {
    arguments.private = true;
  } else if res.is_present("public") {
    arguments.private = false;
  }
  if res.is_present("anon") {
    arguments.auth = false;
  } else if res.is_present("auth") {
    arguments.auth = true;
  }
  if res.is_present("copy") {
    arguments.copy = true;
  } else if res.is_present("no-copy") {
    arguments.copy = false;
  }
  Ok(arguments)
}
<commit_msg>fix(arguments): change --json help message and conflicts<commit_after>use bins::error::*;
use bins::Bins;
use bins::configuration::BinsConfiguration;
use bins::engines;
use bins::FlexibleRange;
use bins::network;
use clap::{App, Arg};
use hyper::Url;
use std::path::Path;
use std::process;

pub struct Arguments {
  pub all: bool,
  pub auth: bool,
  pub copy: bool,
  pub files: Vec<String>,
  pub force: bool,
  pub input: Option<String>,
  pub json: bool,
  pub message: Option<String>,
  pub name: Option<String>,
  pub number_lines: bool,
  pub output: Option<String>,
  pub private: bool,
  pub range: Option<FlexibleRange>,
  pub raw_urls: bool,
  pub server: Option<Url>,
  pub service: Option<String>,
  pub urls: bool,
  pub write: bool
}

include!(concat!(env!("OUT_DIR"), "/git_short_tag.rs"));

fn get_name() -> String {
  option_env!("CARGO_PKG_NAME").unwrap_or("unknown_name").to_owned()
}

fn get_version() -> String {
  let version = option_env!("CARGO_PKG_VERSION").unwrap_or("unknown_version").to_owned();
  let git_tag = git_short_tag();
  format!("{}{}", version, git_tag)
}

cfg_if! {
  if #[cfg(feature = "clipboard_support")] {
    fn get_clipboard_args<'a, 'b>() -> Vec<Arg<'a, 'b>> {
      vec![Arg::with_name("copy")
             .short("C")
             .long("copy")
             .help("copies the output of the command to the clipboard without a newline")
             .conflicts_with("no-copy"),
           Arg::with_name("no-copy")
             .short("c")
             .long("no-copy")
             .help("does not copy the output of the command to the clipboard")]
    }
  } else {
    fn get_clipboard_args<'a, 'b>() -> Vec<Arg<'a, 'b>> {
      Vec::new()
    }
  }
}

pub fn get_arguments(config: &BinsConfiguration) -> Result<Arguments> {
  let mut arguments = Arguments {
    all: false,
    auth: config.get_defaults_auth(),
    copy: config.get_defaults_copy(),
    files: Vec::new(),
    force: false,
    input: None,
    json: false,
    message: None,
    name: None,
    number_lines: false,
    output: None,
    private: config.get_defaults_private(),
    range: None,
    raw_urls: false,
    server: None,
    service: config.get_defaults_service().map(|s| s.to_owned()),
    urls: false,
    write: false
  };
  let name = get_name();
  let version = get_version();
  let mut app = App::new(name.as_ref())
    .version(version.as_ref())
    .about("A tool for pasting from the terminal")
    .arg(Arg::with_name("files")
      .help("files to paste")
      .takes_value(true)
      .multiple(true))
    .arg(Arg::with_name("message")
      .short("m")
      .long("message")
      .help("message to paste")
      .use_delimiter(false)
      .takes_value(true)
      .value_name("string"))
    .arg(Arg::with_name("private")
      .short("p")
      .long("private")
      .help("if the paste should be private")
      .conflicts_with("public"))
    .arg(Arg::with_name("public")
      .short("P")
      .long("public")
      .help("if the paste should be public"))
    .arg(Arg::with_name("auth")
      .short("a")
      .long("auth")
      .help("if authentication (like api keys and tokens) should be used")
      .conflicts_with("anon"))
    .arg(Arg::with_name("anon")
      .short("A")
      .long("anon")
      .help("if pastes should be posted without authentication"))
    .arg(Arg::with_name("service")
      .short("s")
      .long("service")
      .help("pastebin service to use")
      .takes_value(true)
      .possible_values(&*engines::get_bin_names())
      .required(arguments.service.is_none()))
    .arg(Arg::with_name("list-services")
      .short("l")
      .long("list-services")
      .help("lists available bins and exits")
      .conflicts_with_all(&["files", "message", "private", "public", "auth", "anon", "service", "input"]))
    .arg(Arg::with_name("input")
      .short("i")
      .long("input")
      .help("displays raw contents of input paste")
      .takes_value(true)
      .value_name("url")
      .conflicts_with_all(&["auth", "anon", "public", "private", "message", "service"]))
    .arg(Arg::with_name("range")
      .short("n")
      .long("range")
      .help("chooses the files to get in input mode, starting from 0 (e.g. \"0\", \"0,1\", \"0-2\", \"2-0,3\")")
      .takes_value(true)
      .value_name("range")
      .use_delimiter(false)
      .requires("input")
      .conflicts_with("files"))
    .arg(Arg::with_name("all")
      .short("L")
      .long("all")
      .help("gets all files in input mode")
      .requires("input")
      .conflicts_with_all(&["files", "range"]))
    .arg(Arg::with_name("raw-urls")
      .short("r")
      .long("raw-urls")
      .help("gets the raw urls instead of the content in input mode")
      .requires("input"))
    .arg(Arg::with_name("urls")
      .short("u")
      .long("urls")
      .help("gets the urls instead of the content in input mode")
      .requires("input")
      .conflicts_with("raw-urls"))
    .arg(Arg::with_name("server")
      .short("S")
      .long("server")
      .help("specifies the server to use for the service (only support on hastebin)")
      .takes_value(true)
      .value_name("server_url"))
    .arg(Arg::with_name("name")
      .short("N")
      .long("name")
      .help("specifies a file name for --message or stdin")
      .takes_value(true)
      .value_name("name")
      .conflicts_with("files"))
    .arg(Arg::with_name("force")
      .short("f")
      .long("force")
      .help("overrides warnings about file type or size when uploading")
      .conflicts_with("input"))
    .arg(Arg::with_name("number_lines")
      .short("e")
      .long("number-lines")
      .help("display line numbers for each file in input mode")
      .requires("input"))
    .arg(Arg::with_name("write")
      .short("w")
      .long("write")
      .help("writes pastes to files in input mode")
      .requires("input"))
    .arg(Arg::with_name("output")
      .short("o")
      .long("output")
      .help("specifies where to save files in write mode")
      .takes_value(true)
      .value_name("dir")
      .requires("write"))
    .arg(Arg::with_name("json")
      .short("j")
      .long("json")
      .help("output json a object instead of normal values")
      .conflicts_with_all(&["write", "urls", "raw-urls"]));
  for arg in get_clipboard_args() {
    app = app.arg(arg);
  }
  let res = app.get_matches();
  if res.is_present("list-services") {
    println!("{}", engines::get_bin_names().join("\n"));
    process::exit(0);
  }
  if let Some(files) = res.values_of("files") {
    arguments.files = files.map(|s| s.to_owned()).collect();
  }
  if let Some(message) = res.value_of("message") {
    arguments.message = Some(message.to_owned());
  }
  if let Some(service) = res.value_of("service") {
    arguments.service = Some(service.to_owned());
  }
  if let Some(input) = res.value_of("input") {
    arguments.input = Some(input.to_owned());
  }
  if let Some(range) = res.value_of("range") {
    arguments.range = Some(try!(FlexibleRange::parse(range)));
  }
  if let Some(server) = res.value_of("server") {
    if let Some(ref service) = arguments.service {
      if service.to_lowercase() != "hastebin" {
        return Err("--server may only be used if --service is hastebin".into());
      }
    }
    arguments.server = Some(try!(network::parse_url(server).chain_err(|| "invalid --server")));
  }
  if let Some(name) = res.value_of("name") {
    let name = try!(Bins::sanitize_path(Path::new(name)));
    arguments.name = Some(name.to_owned());
  }
  if let Some(output) = res.value_of("output") {
    arguments.output = Some(output.to_owned());
  }
  arguments.all = res.is_present("all");
  arguments.force = res.is_present("force");
  arguments.json = res.is_present("json");
  arguments.number_lines = res.is_present("number_lines");
  arguments.raw_urls = res.is_present("raw-urls");
  arguments.urls = res.is_present("urls");
  arguments.write = res.is_present("write");
  if res.is_present("private") {
    arguments.private = true;
  } else if res.is_present("public") {
    arguments.private = false;
  }
  if res.is_present("anon") {
    arguments.auth = false;
  } else if res.is_present("auth") {
    arguments.auth = true;
  }
  if res.is_present("copy") {
    arguments.copy = true;
  } else if res.is_present("no-copy") {
    arguments.copy = false;
  }
  Ok(arguments)
}
<|endoftext|>


<commit_before>/// The parse modes for messages.
pub enum ParseMode {
    Markdown,
    Html,
    Text,
}

/// Does pattern matching on the `ParseMode` and gets the right `String`.
pub fn get_parse_mode(parse_mode: &ParseMode) -> String {
    match parse_mode {
            &ParseMode::Text => "None",
            &ParseMode::Markdown => "Markdown",
            &ParseMode::Html => "HTML",
    }
    .to_string()
}

<commit_msg>removed white line<commit_after>/// The parse modes for messages.
pub enum ParseMode {
    Markdown,
    Html,
    Text,
}

/// Does pattern matching on the `ParseMode` and gets the right `String`.
pub fn get_parse_mode(parse_mode: &ParseMode) -> String {
    match parse_mode {
            &ParseMode::Text => "None",
            &ParseMode::Markdown => "Markdown",
            &ParseMode::Html => "HTML",
    }
    .to_string()
}
<|endoftext|>


<commit_before>mod table;
mod entry;
mod mapper;
mod utils;

pub use self::mapper::{Mapper, active_mapper};

use common::*;
use core::marker::PhantomData;
use core::ptr::Unique;

use super::{UntypedCapability, MemoryBlock,
            FrameCapability};
use self::mapper::{switch_mapper};
use self::table::{PageTable, PageTableLevel4, PageTableLevel3, PageTableLevel2, PageTableLevel1};
use self::utils::{Page};

use x86::controlregs;

pub struct PageTableCapability {
    p4_block: MemoryBlock,
    active_mappable_virtual_start_addr: usize,
    active_mappable_count: usize,
    useless: bool,
}

impl PageTableCapability {
    pub fn p4_block(&self) -> &MemoryBlock {
        &self.p4_block
    }

    fn map_addr(&self, frame_addr: usize, dest_addr: usize, flags: EntryFlags) {
        let page = Page::new(dest_addr);

        unsafe {
            active_mapper().borrow_mut_map(self.p4_block().start_addr(), 1, |p4 : &mut PageTable<PageTableLevel4>, mapper| {
                mapper.borrow_mut_map(p4[page.p4_index()].physical_address().unwrap(), 1, |p3 : &mut PageTable<PageTableLevel3>, mapper| {
                    mapper.borrow_mut_map(p3[page.p3_index()].physical_address().unwrap(), 1, |p2 : &mut PageTable<PageTableLevel2>, mapper| {
                        mapper.borrow_mut_map(p2[page.p2_index()].physical_address().unwrap(), 1, |p1 : &mut PageTable<PageTableLevel1>, mapper| {
                            assert!(p1[page.p1_index()].is_unused());
                            p1[page.p1_index()].set_address(frame_addr, flags | PRESENT);
                        })
                    })
                })
            })
        }
    }

    pub unsafe fn create_tables_and_map_vga_buffer(&mut self, untyped: &mut UntypedCapability) {
        self.create_tables(0xb8000, 1, untyped);
        self.map_addr(0xb8000, 0xb8000, WRITABLE);
    }

    pub fn create_tables(&mut self, dest_addr: usize, count: usize, untyped: &mut UntypedCapability) {
        for i in 0..count {
            let page = Page::new(dest_addr + i * PAGE_SIZE);

            unsafe {
                active_mapper().borrow_mut_map(self.p4_block().start_addr(), 1, |p4 : &mut PageTable<PageTableLevel4>, mapper| {
                    p4.next_table_create(page.p4_index(), untyped, mapper, |p3, untyped, mapper| {
                        p3.next_table_create(page.p3_index(), untyped, mapper, |p2, untyped, mapper| {
                            p2.next_table_create(page.p2_index(), untyped, mapper, |p1, untyped, mapper| { })
                        })
                    })
                });
            }
        }
    }

    pub fn map(&mut self, mut frame: FrameCapability, dest_addr: usize) {
        for i in 0..frame.count() {
            let frame_addr = frame.block().start_addr() + i * PAGE_SIZE;
            let flags = frame.flags();
            self.map_addr(frame_addr, dest_addr + i * PAGE_SIZE, flags);
        }

        unsafe { frame.mark_useless(); }
    }

    pub fn identity_map(&mut self, frame: FrameCapability) {
        let dest_addr = frame.block().start_addr();
        self.map(frame, dest_addr)
    }

    pub fn create_tables_and_map(&mut self, frame: FrameCapability, dest_addr: usize, untyped: &mut UntypedCapability) {
        let frame_start_addr = frame.block().start_addr();
        let frame_count = frame.count();

        self.create_tables(dest_addr, frame_count, untyped);
        self.map(frame, dest_addr);
    }

    pub fn create_tables_and_identity_map(&mut self, frame: FrameCapability, untyped: &mut UntypedCapability) {
        let dest_addr = frame.block().start_addr();

        self.create_tables_and_map(frame, dest_addr, untyped);
    }

    pub unsafe fn switch_on(&self) {
        switch_mapper(self.active_mappable_virtual_start_addr, self.active_mappable_count);
        controlregs::cr3_write(self.p4_block().start_addr() as u64);
    }

    pub unsafe fn mark_useless(&mut self) {
        self.useless = true;
    }

    pub fn from_untyped(untyped: &mut UntypedCapability, active_mappable_virtual_start_addr: usize, active_mappable_count: usize) -> PageTableCapability {
        let p4_block = untyped.retype(PAGE_SIZE, PAGE_SIZE);

        unsafe {
            active_mapper().borrow_mut_map(p4_block.start_addr(), 1, |p4 : &mut PageTable<PageTableLevel4>, mapper| {
                p4.zero();
                p4[511].set_address(p4_block.start_addr(), PRESENT | WRITABLE);
            });
        }

        let mut target = PageTableCapability {
            p4_block: p4_block,
            active_mappable_virtual_start_addr: active_mappable_virtual_start_addr,
            active_mappable_count: active_mappable_count,
            useless: false,
        };

        target.create_tables(active_mappable_virtual_start_addr, active_mappable_count, untyped);

        target
    }
}

impl Drop for PageTableCapability{
    fn drop(&mut self) {
        unsafe { self.p4_block.mark_useless(); }
        if self.useless { return; }

        unimplemented!();
    }
}
<commit_msg>WIP: unmapping for paging mod<commit_after>mod table;
mod entry;
mod mapper;
mod utils;

pub use self::mapper::{Mapper, active_mapper};

use common::*;
use core::marker::PhantomData;
use core::ptr::Unique;

use super::{UntypedCapability, MemoryBlock,
            FrameCapability};
use self::mapper::{switch_mapper};
use self::table::{PageTable, PageTableLevel4, PageTableLevel3, PageTableLevel2, PageTableLevel1};
use self::utils::{Page};

use x86::controlregs;

pub struct PageTableCapability {
    p4_block: MemoryBlock,
    active_mappable_virtual_start_addr: usize,
    active_mappable_count: usize,
    useless: bool,
}

impl PageTableCapability {
    pub fn p4_block(&self) -> &MemoryBlock {
        &self.p4_block
    }

    fn map_addr(&self, frame_addr: usize, dest_addr: usize, flags: EntryFlags) {
        let page = Page::new(dest_addr);

        unsafe {
            active_mapper().borrow_mut_map(self.p4_block().start_addr(), 1, |p4 : &mut PageTable<PageTableLevel4>, mapper| {
                mapper.borrow_mut_map(p4[page.p4_index()].physical_address().unwrap(), 1, |p3 : &mut PageTable<PageTableLevel3>, mapper| {
                    mapper.borrow_mut_map(p3[page.p3_index()].physical_address().unwrap(), 1, |p2 : &mut PageTable<PageTableLevel2>, mapper| {
                        mapper.borrow_mut_map(p2[page.p2_index()].physical_address().unwrap(), 1, |p1 : &mut PageTable<PageTableLevel1>, mapper| {
                            assert!(p1[page.p1_index()].is_unused());
                            p1[page.p1_index()].set_address(frame_addr, flags | PRESENT);
                        })
                    })
                })
            })
        }
    }

    fn unmap_addr(&self, dest_addr: usize) -> PhysicalAddress {
        let page = Page::new(dest_addr);

        unsafe {
            let mut frame_addr = None;

            active_mapper().borrow_mut_map(self.p4_block().start_addr(), 1, |p4 : &mut PageTable<PageTableLevel4>, mapper| {
                mapper.borrow_mut_map(p4[page.p4_index()].physical_address().unwrap(), 1, |p3 : &mut PageTable<PageTableLevel3>, mapper| {
                    mapper.borrow_mut_map(p3[page.p3_index()].physical_address().unwrap(), 1, |p2 : &mut PageTable<PageTableLevel2>, mapper| {
                        mapper.borrow_mut_map(p2[page.p2_index()].physical_address().unwrap(), 1, |p1 : &mut PageTable<PageTableLevel1>, mapper| {
                            assert!(!p1[page.p1_index()].is_unused());
                            frame_addr = p1[page.p1_index()].physical_address();
                            p1[page.p1_index()].set_unused();
                        })
                    })
                })
            });

            frame_addr.unwrap()
        }
    }

    pub unsafe fn create_tables_and_map_vga_buffer(&mut self, untyped: &mut UntypedCapability) {
        self.create_tables(0xb8000, 1, untyped);
        self.map_addr(0xb8000, 0xb8000, WRITABLE);
    }

    pub fn create_tables(&mut self, dest_addr: usize, count: usize, untyped: &mut UntypedCapability) {
        for i in 0..count {
            let page = Page::new(dest_addr + i * PAGE_SIZE);

            unsafe {
                active_mapper().borrow_mut_map(self.p4_block().start_addr(), 1, |p4 : &mut PageTable<PageTableLevel4>, mapper| {
                    p4.next_table_create(page.p4_index(), untyped, mapper, |p3, untyped, mapper| {
                        p3.next_table_create(page.p3_index(), untyped, mapper, |p2, untyped, mapper| {
                            p2.next_table_create(page.p2_index(), untyped, mapper, |p1, untyped, mapper| { })
                        })
                    })
                });
            }
        }
    }

    pub fn map(&mut self, mut frame: FrameCapability, dest_addr: usize) {
        for i in 0..frame.count() {
            let frame_addr = frame.block().start_addr() + i * PAGE_SIZE;
            let flags = frame.flags();
            self.map_addr(frame_addr, dest_addr + i * PAGE_SIZE, flags);
        }

        unsafe { frame.mark_useless(); }
    }

    pub fn unmap(&mut self, dest_addr: usize) -> FrameCapability {
        unimplemented!()
    }

    pub fn identity_map(&mut self, frame: FrameCapability) {
        let dest_addr = frame.block().start_addr();
        self.map(frame, dest_addr)
    }

    pub fn create_tables_and_map(&mut self, frame: FrameCapability, dest_addr: usize, untyped: &mut UntypedCapability) {
        let frame_start_addr = frame.block().start_addr();
        let frame_count = frame.count();

        self.create_tables(dest_addr, frame_count, untyped);
        self.map(frame, dest_addr);
    }

    pub fn create_tables_and_identity_map(&mut self, frame: FrameCapability, untyped: &mut UntypedCapability) {
        let dest_addr = frame.block().start_addr();

        self.create_tables_and_map(frame, dest_addr, untyped);
    }

    pub unsafe fn switch_on(&self) {
        switch_mapper(self.active_mappable_virtual_start_addr, self.active_mappable_count);
        controlregs::cr3_write(self.p4_block().start_addr() as u64);
    }

    pub unsafe fn mark_useless(&mut self) {
        self.useless = true;
    }

    pub fn from_untyped(untyped: &mut UntypedCapability, active_mappable_virtual_start_addr: usize, active_mappable_count: usize) -> PageTableCapability {
        let p4_block = untyped.retype(PAGE_SIZE, PAGE_SIZE);

        unsafe {
            active_mapper().borrow_mut_map(p4_block.start_addr(), 1, |p4 : &mut PageTable<PageTableLevel4>, mapper| {
                p4.zero();
                p4[511].set_address(p4_block.start_addr(), PRESENT | WRITABLE);
            });
        }

        let mut target = PageTableCapability {
            p4_block: p4_block,
            active_mappable_virtual_start_addr: active_mappable_virtual_start_addr,
            active_mappable_count: active_mappable_count,
            useless: false,
        };

        target.create_tables(active_mappable_virtual_start_addr, active_mappable_count, untyped);

        target
    }
}

impl Drop for PageTableCapability{
    fn drop(&mut self) {
        unsafe { self.p4_block.mark_useless(); }
        if self.useless { return; }

        unimplemented!();
    }
}
<|endoftext|>


<commit_before>use chattium_oxide_lib::json::FromJsonnable;
use chattium_oxide_lib::ChatMessage;
use hyper::server::{Request, Response};
use hyper::header::ContentLength;
use hyper::status::StatusCode;
use hyper::method::Method;
use time::strftime;
use std::io::{Read, Write, stderr};

pub fn handle_client(req: Request, mut res: Response) {
	let mut req = req;
	let mut body = format!("{}, use https://github.com/nabijaczleweli/chattium-oxide-client to connect to chat", req.remote_addr);

	*res.status_mut() = match req.method {
		Method::Post => {
			let mut reqbody = String::new();
			match req.read_to_string(&mut reqbody) {
				Ok(_) =>
					match ChatMessage::from_json_string(&reqbody) {
						Ok(mut message) => {
							message.sender.fill_ip(req.remote_addr);
							println!("{}: {} @ {}", message.sender.name, message.value, strftime("%T", &message.time_posted).unwrap());
							StatusCode::Ok
						},
						Err(error) => {
							let _ = stderr().write_fmt(format_args!("Couldn't process POSTed message from {}: {}", req.remote_addr, error));
							StatusCode::UnprocessableEntity
						},
					},
				Err(error) => {
					let _ = stderr().write_fmt(format_args!("Failed reading request from {}: {}", req.remote_addr, error));
					StatusCode::UnsupportedMediaType  // non-UTF-8
				},
			}
		},
	  _ => StatusCode::ImATeapot,
	};

	res.headers_mut().set(ContentLength(body.len() as u64));
	if let Err(error) = res.start().unwrap().write_all(body.as_bytes()) {
		let _ = stderr().write_fmt(format_args!("Failed to respond to {}: {}", req.remote_addr, error));
	}
}
<commit_msg>Match on reading first, then on response type<commit_after>use chattium_oxide_lib::json::FromJsonnable;
use chattium_oxide_lib::ChatMessage;
use hyper::server::{Request, Response};
use hyper::header::ContentLength;
use hyper::status::StatusCode;
use hyper::method::Method;
use time::strftime;
use std::io::{Read, Write, stderr};

pub fn handle_client(req: Request, mut res: Response) {
	let mut req = req;
	let mut body = format!("{}, use https://github.com/nabijaczleweli/chattium-oxide-client to connect to chat", req.remote_addr);

	let mut reqbody = String::new();
	*res.status_mut() = match req.read_to_string(&mut reqbody) {
		Ok(_) =>
			match req.method {
				Method::Post =>
					match ChatMessage::from_json_string(&reqbody) {
						Ok(mut message) => {
							message.sender.fill_ip(req.remote_addr);
							println!("{}: {} @ {}", message.sender.name, message.value, strftime("%T", &message.time_posted).unwrap());
							StatusCode::Ok
						},
						Err(error) => {
							let _ = stderr().write_fmt(format_args!("Couldn't process POSTed message from {}: {}", req.remote_addr, error));
							StatusCode::UnprocessableEntity
						},
					},
			  _ => StatusCode::ImATeapot,
			},
		Err(error) => {
			let _ = stderr().write_fmt(format_args!("Failed reading request from {}: {}", req.remote_addr, error));
			StatusCode::UnsupportedMediaType  // non-UTF-8
		},
	};

	res.headers_mut().set(ContentLength(body.len() as u64));
	if let Err(error) = res.start().unwrap().write_all(body.as_bytes()) {
		let _ = stderr().write_fmt(format_args!("Failed to respond to {}: {}", req.remote_addr, error));
	}
}
<|endoftext|>


<commit_before>use super::super::common::Vec2;
use super::super::common::math::{min_vec, max_vec};

pub struct AABB {
    /// The lower vertex
    pub lower_bound: Vec2,
    /// The upper vertex
    pub upper_bound: Vec2
}

impl AABB {
    pub fn new() -> AABB {
        AABB {
            lower_bound: Vec2::zero(),
            upper_bound: Vec2::zero()
        }
    }

    /// Verify that the bounds are sorted.
    pub fn is_valid(self) -> bool {
        let d = self.upper_bound - self.lower_bound;
        let mut valid = d.x >= 0.0 && d.y >= 0.0;
        valid = valid && self.lower_bound.is_valid() && self.upper_bound.is_valid();
        return valid;
    }

    /// Get the center of the AABB.
    pub fn get_center(self) -> Vec2 {
        0.5 * (self.lower_bound + self.upper_bound)
    }

    /// Get the extents of the AABB (half-widths).
    pub fn get_extents(self) -> Vec2 {
        0.5 * (self.upper_bound - self.lower_bound)
    }

    /// Get the perimeter length
    pub fn get_perimeter(self) -> f32 {
        let wx = self.upper_bound.x - self.lower_bound.x;
        let wy = self.upper_bound.y - self.upper_bound.y;
        2.0 * (wx + wy)
    }

    /// Combine an AABB into this one.
    pub fn combine(&mut self, aabb: AABB) {
        self.lower_bound = min_vec(self.lower_bound, aabb.lower_bound);
        self.upper_bound = max_vec(self.upper_bound, aabb.upper_bound);
    }

    /// Combine two AABBs into this one
    pub fn combine_two(&mut self, aabb1: AABB, aabb2: AABB) {
        self.lower_bound = min_vec(aabb1.lower_bound, aabb2.lower_bound);
        self.upper_bound = max_vec(aabb1.upper_bound, aabb2.upper_bound);
    }

    /// Does this aabb contain the procided AABB.
    pub fn contains(&mut self, aabb: AABB) -> bool {
        let mut result = true;
        result = result && self.lower_bound.x <= aabb.lower_bound.x;
        result = result && self.lower_bound.y <= aabb.lower_bound.y;
        result = result && aabb.upper_bound.x <= self.upper_bound.x;
        result = result && aabb.upper_bound.y <= self.upper_bound.y;
        return result;
    }

    // TODO implement ray_cast
    // pub fn ray_cast(input: RayCastInput) -> RayCastOutput
}
<commit_msg>Adding AABB overlap function<commit_after>use super::super::common::Vec2;
use super::super::common::math::{min_vec, max_vec};

pub struct AABB {
    /// The lower vertex
    pub lower_bound: Vec2,
    /// The upper vertex
    pub upper_bound: Vec2
}

impl AABB {
    pub fn new() -> AABB {
        AABB {
            lower_bound: Vec2::zero(),
            upper_bound: Vec2::zero()
        }
    }

    /// Verify that the bounds are sorted.
    pub fn is_valid(self) -> bool {
        let d = self.upper_bound - self.lower_bound;
        let mut valid = d.x >= 0.0 && d.y >= 0.0;
        valid = valid && self.lower_bound.is_valid() && self.upper_bound.is_valid();
        return valid;
    }

    /// Get the center of the AABB.
    pub fn get_center(self) -> Vec2 {
        0.5 * (self.lower_bound + self.upper_bound)
    }

    /// Get the extents of the AABB (half-widths).
    pub fn get_extents(self) -> Vec2 {
        0.5 * (self.upper_bound - self.lower_bound)
    }

    /// Get the perimeter length
    pub fn get_perimeter(self) -> f32 {
        let wx = self.upper_bound.x - self.lower_bound.x;
        let wy = self.upper_bound.y - self.upper_bound.y;
        2.0 * (wx + wy)
    }

    /// Combine an AABB into this one.
    pub fn combine(&mut self, aabb: AABB) {
        self.lower_bound = min_vec(self.lower_bound, aabb.lower_bound);
        self.upper_bound = max_vec(self.upper_bound, aabb.upper_bound);
    }

    /// Combine two AABBs into this one
    pub fn combine_two(&mut self, aabb1: AABB, aabb2: AABB) {
        self.lower_bound = min_vec(aabb1.lower_bound, aabb2.lower_bound);
        self.upper_bound = max_vec(aabb1.upper_bound, aabb2.upper_bound);
    }

    /// Does this aabb contain the procided AABB.
    pub fn contains(&mut self, aabb: AABB) -> bool {
        let mut result = true;
        result = result && self.lower_bound.x <= aabb.lower_bound.x;
        result = result && self.lower_bound.y <= aabb.lower_bound.y;
        result = result && aabb.upper_bound.x <= self.upper_bound.x;
        result = result && aabb.upper_bound.y <= self.upper_bound.y;
        return result;
    }

    // TODO implement ray_cast
    // pub fn ray_cast(input: RayCastInput) -> RayCastOutput
}

/// Determine if AABB overlap
pub fn test_aabb_overlap(a: AABB, b: AABB) -> bool {
    let d1 = b.lower_bound - a.upper_bound;
    let d2 = a.lower_bound - b.upper_bound;

    if d1.x > 0.0 || d1.y > 0.0 {
        return false;
    }

    if d2.x > 0.0 || d2.y > 0.0 {
        return false;
    }

    return true;
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};

pub enum Transfer {
    None,
    Container,
    Full,
}

impl Transfer {
    pub fn by_name(name: &str) -> Option<Transfer> {
        use self::Transfer::*;
        match name {
            "none" => Some(None),
            "container" => Some(Container),
            "full" => Some(Full),
            _ => Option::None,
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Fundamental {
    None,
    Boolean,
    Int8,
    UInt8,
    Int16,
    UInt16,
    Int32,
    UInt32,
    Int64,
    UInt64,
    Char,
    UChar,
    Int,
    UInt,
    Long,
    ULong,
    Size,
    SSize,
    Float,
    Double,
    Pointer,
    VarArgs,
    UniChar,
    Utf8,
    Filename,
    Type,
    Unsupported,
}

pub const FUNDAMENTAL: [(&'static str, Fundamental); 28] = [
    ("none", Fundamental::None),
    ("gboolean", Fundamental::Boolean),
    ("gint8", Fundamental::Int8),
    ("guint8", Fundamental::UInt8),
    ("gint16", Fundamental::Int16),
    ("guint16", Fundamental::UInt16),
    ("gint32", Fundamental::Int32),
    ("guint32", Fundamental::UInt32),
    ("gint64", Fundamental::Int64),
    ("guint64", Fundamental::UInt64),
    ("gchar", Fundamental::Char),
    ("guchar", Fundamental::UChar),
    ("gint", Fundamental::Int),
    ("guint", Fundamental::UInt),
    ("glong", Fundamental::Long),
    ("gulong", Fundamental::ULong),
    ("gsize", Fundamental::Size),
    ("gssize", Fundamental::SSize),
    ("gfloat", Fundamental::Float),
    ("gdouble", Fundamental::Double),
    ("long double", Fundamental::Unsupported),
    ("gunichar", Fundamental::UniChar),
    ("gpointer", Fundamental::Pointer),
    ("va_list", Fundamental::Unsupported),
    ("varargs", Fundamental::VarArgs),
    ("utf8", Fundamental::Utf8),
    ("filename", Fundamental::Filename),
    ("GType", Fundamental::Type),
];

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct TypeId {
    ns_id: u16,
    id: u32,
}

pub struct Alias {
    pub name: String,
    pub c_identifier: String,
    pub typ: TypeId,
}

pub struct Constant {
    pub name: String,
    pub typ: TypeId,
    pub value: String,
}

pub struct Member {
    pub name: String,
    pub c_identifier: String,
    pub value: String,
}

pub struct Enumeration {
    pub name: String,
    pub glib_name: String,
    pub members: Vec<Member>,
    pub functions: Vec<Function>,
}

pub struct Bitfield {
    pub name: String,
    pub glib_name: String,
    pub members: Vec<Member>,
    pub functions: Vec<Function>,
}

pub struct Record {
    pub name: String,
    pub glib_name: String,
    pub functions: Vec<Function>,
}

pub struct Field {
    pub name: String,
    pub typ: TypeId,
}

pub struct Union {
    pub name: String,
    pub glib_name: String,
    pub fields: Vec<Field>,
    pub functions: Vec<Function>,
}

pub struct Parameter {
    pub name: String,
    pub typ: TypeId,
    pub transfer: Transfer,
}

pub struct Function {
    pub name: String,
    pub c_identifier: String,
    pub parameters: Vec<Parameter>,
    pub ret: Parameter,
}

pub struct Interface {
    pub name: String,
    pub glib_name: String,
    pub functions: Vec<Function>,
}

pub struct Class {
    pub name: String,
    pub glib_name: String,
    pub functions: Vec<Function>,
    pub parent: Option<TypeId>,
    pub implements: Vec<TypeId>,
}

pub enum Type {
    Fundamental(Fundamental),
    Alias(Alias),
    Enumeration(Enumeration),
    Bitfield(Bitfield),
    Record(Record),
    Union(Union),
    Callback(Function),
    Interface(Interface),
    Class(Class),
    Array(TypeId),
    HashTable(TypeId, TypeId),
    List(TypeId),
    SList(TypeId),
}

impl Type {
    pub fn container(library: &mut Library, name: &str, mut inner: Vec<TypeId>) -> Option<TypeId> {
        match (name, inner.len()) {
            ("array", 1) => {
                let tid = inner.remove(0);
                Some((format!("array(#{:?})", tid), Type::Array(tid)))
            }
            ("GLib.HashTable", 2) => {
                let k_tid = inner.remove(0);
                let v_tid = inner.remove(0);
                Some((format!("HashTable(#{:?}, #{:?})", k_tid, v_tid), Type::HashTable(k_tid, v_tid)))
            }
            ("GLib.List", 1) => {
                let tid = inner.remove(0);
                Some((format!("List(#{:?})", tid), Type::List(tid)))
            }
            ("GLib.SList", 1) => {
                let tid = inner.remove(0);
                Some((format!("SList(#{:?})", tid), Type::SList(tid)))
            }
            _ => None,
        }.map(|(name, typ)| library.add_type(INTERNAL_NAMESPACE, &name, typ))
    }
}

pub trait AsArg {
    fn as_arg(&self, library: &Library) -> String;
}

impl AsArg for Fundamental {
    fn as_arg(&self, _: &Library) -> String {
        use self::Fundamental::*;
        match *self {
            Boolean => "gboolean",
            Int8 => "gint8",
            UInt8 => "guint8",
            Int16 => "gint16",
            UInt16 => "guint16",
            Int32 => "gint32",
            UInt32 => "guint32",
            Int64 => "gint64",
            UInt64 => "guint64",
            Char => "gchar",
            UChar => "guchar",
            Int => "gint",
            UInt => "guint",
            Long => "glong",
            ULong => "gulong",
            Size => "gsize",
            SSize => "gssize",
            Float => "gfloat",
            Double => "gdouble",
            UniChar => "gunichar",
            Pointer => "gpointer",
            VarArgs => "...",
            Utf8 => "*const c_char",
            Filename => "*const c_char",
            Type => "GType",
            None => "c_void",
            Unsupported => panic!("unsupported type"),
        }.into()
    }
}

impl AsArg for Type {
    fn as_arg(&self, library: &Library) -> String {
        use self::Type::*;
        match *self {
            Fundamental(ref x) => x.as_arg(library),
            Alias(ref x) => library.type_(x.typ).as_arg(library),
            Enumeration(ref x) => x.name.clone(),
            Bitfield(ref x) => x.name.clone(),
            Record(ref x) => format!("*mut {}", &x.name),
            Union(ref x) => format!("*mut {}", &x.name),
            Callback(_) => "TODO".into(),
            Interface(ref x) => format!("*mut {}", &x.name),
            Class(ref x) => format!("*mut {}", &x.name),
            Array(x) => format!("*mut {}", library.type_(x).as_arg(library)),
            HashTable(_, _)  => "*mut GHashTable".into(),
            List(_)  => "*mut GList".into(),
            SList(_)  => "*mut GSList".into(),
        }
    }
}

pub struct Namespace {
    pub name: String,
    pub types: Vec<Option<Type>>,
    pub index: HashMap<String, u32>,
    pub constants: Vec<Constant>,
    pub functions: Vec<Function>,
}

impl Namespace {
    fn new(name: &str) -> Namespace {
        Namespace {
            name: name.into(),
            types: Vec::new(),
            index: HashMap::new(),
            constants: Vec::new(),
            functions: Vec::new(),
        }
    }

    fn add_constant(&mut self, c: Constant) {
        self.constants.push(c);
    }

    fn add_function(&mut self, f: Function) {
        self.functions.push(f);
    }

    fn type_(&self, id: u32) -> &Type {
        self.types[id as usize].as_ref().unwrap()
    }

    fn type_mut(&mut self, id: u32) -> &mut Type {
        self.types[id as usize].as_mut().unwrap()
    }

    fn add_type(&mut self, name: &str, typ: Option<Type>) -> u32 {
        if let Some(id) = self.find_type(name) {
            self.types[id as usize] = typ;
            id
        }
        else {
            let id = self.types.len() as u32;
            self.types.push(typ);
            self.index.insert(name.into(), id);
            id
        }
    }

    fn find_type(&self, name: &str) -> Option<u32> {
        self.index.get(name).cloned()
    }

    fn unresolved(&self) -> Vec<&str> {
        self.index.iter().filter_map(|(name, &id)| {
            if self.types[id as usize].is_none() {
                Some(&name[..])
            } else {
                None
            }
        }).collect()
    }
}

pub const INTERNAL_NAMESPACE_NAME: &'static str = "*";
pub const INTERNAL_NAMESPACE: u16 = 0;

pub struct Library {
    pub namespaces: Vec<Namespace>,
    pub index: HashMap<String, u16>,
}

impl Library {
    pub fn new() -> Library {
        let mut library = Library {
            namespaces: Vec::new(),
            index: HashMap::new(),
        };
        assert!(library.add_namespace(INTERNAL_NAMESPACE_NAME) == INTERNAL_NAMESPACE);
        library.namespace_mut(INTERNAL_NAMESPACE).name = INTERNAL_NAMESPACE_NAME.into();
        for &(name, t) in &FUNDAMENTAL {
            library.add_type(INTERNAL_NAMESPACE, name, Type::Fundamental(t));
        }
        library
    }

    pub fn namespace(&self, ns_id: u16) -> &Namespace {
        &self.namespaces[ns_id as usize]
    }

    pub fn namespace_mut(&mut self, ns_id: u16) -> &mut Namespace {
        &mut self.namespaces[ns_id as usize]
    }

    pub fn find_namespace(&self, name: &str) -> Option<u16> {
        self.index.get(name).cloned()
    }

    pub fn add_namespace(&mut self, name: &str) -> u16 {
        if let Some(&id) = self.index.get(name) {
            id
        }
        else {
            let id = self.namespaces.len() as u16;
            self.namespaces.push(Namespace::new(name));
            self.index.insert(name.into(), id);
            id
        }
    }

    pub fn add_constant(&mut self, ns_id: u16, c: Constant) {
        self.namespace_mut(ns_id).add_constant(c);
    }

    pub fn add_function(&mut self, ns_id: u16, f: Function) {
        self.namespace_mut(ns_id).add_function(f);
    }

    pub fn add_type(&mut self, ns_id: u16, name: &str, typ: Type) -> TypeId {
        TypeId { ns_id: ns_id, id: self.namespace_mut(ns_id).add_type(name, Some(typ)) }
    }

    pub fn find_type(&self, current_ns_id: u16, name: &str) -> Option<TypeId> {
        let (ns, name) = split_ns_name(name);

        if let Some(ns) = ns {
            self.find_namespace(ns).and_then(|ns_id| {
                self.namespace(ns_id).find_type(name).map(|id| TypeId { ns_id: ns_id, id: id })
            })
        }
        else if let Some(id) = self.namespace(current_ns_id).find_type(name) {
            Some(TypeId { ns_id: current_ns_id, id: id })
        }
        else if let Some(id) = self.namespace(INTERNAL_NAMESPACE).find_type(name) {
            Some(TypeId { ns_id: INTERNAL_NAMESPACE, id: id })
        }
        else {
            None
        }
    }

    pub fn find_or_stub_type(&mut self, current_ns_id: u16, name: &str) -> TypeId {
        if let Some(tid) = self.find_type(current_ns_id, name) {
            return tid;
        }

        let (ns, name) = split_ns_name(name);

        if let Some(ns) = ns {
            let ns_id = self.find_namespace(ns).unwrap_or_else(|| self.add_namespace(ns));
            let ns = self.namespace_mut(ns_id);
            let id = ns.find_type(name).unwrap_or_else(|| ns.add_type(name, None));
            return TypeId { ns_id: ns_id, id: id };
        }

        let id = self.namespace_mut(current_ns_id).add_type(name, None);
        TypeId { ns_id: current_ns_id, id: id }
    }

    pub fn type_(&self, tid: TypeId) -> &Type {
        self.namespace(tid.ns_id).type_(tid.id)
    }

    pub fn type_mut(&mut self, tid: TypeId) -> &Type {
        self.namespace_mut(tid.ns_id).type_mut(tid.id)
    }

    pub fn check_resolved(&self) {
        let list: Vec<_> = self.index.iter().flat_map(|(name, &id)| {
            let name = name.clone();
            self.namespace(id).unresolved().into_iter().map(move |s| format!("{}.{}", name, s))
        }).collect();

        if !list.is_empty() {
            panic!("Incomplete library, unresolved: {:?}", list);
        }
    }
}

fn split_ns_name(name: &str) -> (Option<String>, String) {
    let mut parts = name.split('.');
    let name = parts.next_back().unwrap();
    let ns = parts.next_back();
    assert!(ns.is_none() || parts.next().is_none());
    (ns, name)
}
<commit_msg>Fix the build<commit_after>use std::collections::{HashMap, HashSet};

pub enum Transfer {
    None,
    Container,
    Full,
}

impl Transfer {
    pub fn by_name(name: &str) -> Option<Transfer> {
        use self::Transfer::*;
        match name {
            "none" => Some(None),
            "container" => Some(Container),
            "full" => Some(Full),
            _ => Option::None,
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Fundamental {
    None,
    Boolean,
    Int8,
    UInt8,
    Int16,
    UInt16,
    Int32,
    UInt32,
    Int64,
    UInt64,
    Char,
    UChar,
    Int,
    UInt,
    Long,
    ULong,
    Size,
    SSize,
    Float,
    Double,
    Pointer,
    VarArgs,
    UniChar,
    Utf8,
    Filename,
    Type,
    Unsupported,
}

pub const FUNDAMENTAL: [(&'static str, Fundamental); 28] = [
    ("none", Fundamental::None),
    ("gboolean", Fundamental::Boolean),
    ("gint8", Fundamental::Int8),
    ("guint8", Fundamental::UInt8),
    ("gint16", Fundamental::Int16),
    ("guint16", Fundamental::UInt16),
    ("gint32", Fundamental::Int32),
    ("guint32", Fundamental::UInt32),
    ("gint64", Fundamental::Int64),
    ("guint64", Fundamental::UInt64),
    ("gchar", Fundamental::Char),
    ("guchar", Fundamental::UChar),
    ("gint", Fundamental::Int),
    ("guint", Fundamental::UInt),
    ("glong", Fundamental::Long),
    ("gulong", Fundamental::ULong),
    ("gsize", Fundamental::Size),
    ("gssize", Fundamental::SSize),
    ("gfloat", Fundamental::Float),
    ("gdouble", Fundamental::Double),
    ("long double", Fundamental::Unsupported),
    ("gunichar", Fundamental::UniChar),
    ("gpointer", Fundamental::Pointer),
    ("va_list", Fundamental::Unsupported),
    ("varargs", Fundamental::VarArgs),
    ("utf8", Fundamental::Utf8),
    ("filename", Fundamental::Filename),
    ("GType", Fundamental::Type),
];

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct TypeId {
    ns_id: u16,
    id: u32,
}

pub struct Alias {
    pub name: String,
    pub c_identifier: String,
    pub typ: TypeId,
}

pub struct Constant {
    pub name: String,
    pub typ: TypeId,
    pub value: String,
}

pub struct Member {
    pub name: String,
    pub c_identifier: String,
    pub value: String,
}

pub struct Enumeration {
    pub name: String,
    pub glib_name: String,
    pub members: Vec<Member>,
    pub functions: Vec<Function>,
}

pub struct Bitfield {
    pub name: String,
    pub glib_name: String,
    pub members: Vec<Member>,
    pub functions: Vec<Function>,
}

pub struct Record {
    pub name: String,
    pub glib_name: String,
    pub functions: Vec<Function>,
}

pub struct Field {
    pub name: String,
    pub typ: TypeId,
}

pub struct Union {
    pub name: String,
    pub glib_name: String,
    pub fields: Vec<Field>,
    pub functions: Vec<Function>,
}

pub struct Parameter {
    pub name: String,
    pub typ: TypeId,
    pub transfer: Transfer,
}

pub struct Function {
    pub name: String,
    pub c_identifier: String,
    pub parameters: Vec<Parameter>,
    pub ret: Parameter,
}

pub struct Interface {
    pub name: String,
    pub glib_name: String,
    pub functions: Vec<Function>,
}

pub struct Class {
    pub name: String,
    pub glib_name: String,
    pub functions: Vec<Function>,
    pub parent: Option<TypeId>,
    pub implements: Vec<TypeId>,
}

pub enum Type {
    Fundamental(Fundamental),
    Alias(Alias),
    Enumeration(Enumeration),
    Bitfield(Bitfield),
    Record(Record),
    Union(Union),
    Callback(Function),
    Interface(Interface),
    Class(Class),
    Array(TypeId),
    HashTable(TypeId, TypeId),
    List(TypeId),
    SList(TypeId),
}

impl Type {
    pub fn container(library: &mut Library, name: &str, mut inner: Vec<TypeId>) -> Option<TypeId> {
        match (name, inner.len()) {
            ("array", 1) => {
                let tid = inner.remove(0);
                Some((format!("array(#{:?})", tid), Type::Array(tid)))
            }
            ("GLib.HashTable", 2) => {
                let k_tid = inner.remove(0);
                let v_tid = inner.remove(0);
                Some((format!("HashTable(#{:?}, #{:?})", k_tid, v_tid), Type::HashTable(k_tid, v_tid)))
            }
            ("GLib.List", 1) => {
                let tid = inner.remove(0);
                Some((format!("List(#{:?})", tid), Type::List(tid)))
            }
            ("GLib.SList", 1) => {
                let tid = inner.remove(0);
                Some((format!("SList(#{:?})", tid), Type::SList(tid)))
            }
            _ => None,
        }.map(|(name, typ)| library.add_type(INTERNAL_NAMESPACE, &name, typ))
    }
}

pub trait AsArg {
    fn as_arg(&self, library: &Library) -> String;
}

impl AsArg for Fundamental {
    fn as_arg(&self, _: &Library) -> String {
        use self::Fundamental::*;
        match *self {
            Boolean => "gboolean",
            Int8 => "gint8",
            UInt8 => "guint8",
            Int16 => "gint16",
            UInt16 => "guint16",
            Int32 => "gint32",
            UInt32 => "guint32",
            Int64 => "gint64",
            UInt64 => "guint64",
            Char => "gchar",
            UChar => "guchar",
            Int => "gint",
            UInt => "guint",
            Long => "glong",
            ULong => "gulong",
            Size => "gsize",
            SSize => "gssize",
            Float => "gfloat",
            Double => "gdouble",
            UniChar => "gunichar",
            Pointer => "gpointer",
            VarArgs => "...",
            Utf8 => "*const c_char",
            Filename => "*const c_char",
            Type => "GType",
            None => "c_void",
            Unsupported => panic!("unsupported type"),
        }.into()
    }
}

impl AsArg for Type {
    fn as_arg(&self, library: &Library) -> String {
        use self::Type::*;
        match *self {
            Fundamental(ref x) => x.as_arg(library),
            Alias(ref x) => library.type_(x.typ).as_arg(library),
            Enumeration(ref x) => x.name.clone(),
            Bitfield(ref x) => x.name.clone(),
            Record(ref x) => format!("*mut {}", &x.name),
            Union(ref x) => format!("*mut {}", &x.name),
            Callback(_) => "TODO".into(),
            Interface(ref x) => format!("*mut {}", &x.name),
            Class(ref x) => format!("*mut {}", &x.name),
            Array(x) => format!("*mut {}", library.type_(x).as_arg(library)),
            HashTable(_, _)  => "*mut GHashTable".into(),
            List(_)  => "*mut GList".into(),
            SList(_)  => "*mut GSList".into(),
        }
    }
}

pub struct Namespace {
    pub name: String,
    pub types: Vec<Option<Type>>,
    pub index: HashMap<String, u32>,
    pub constants: Vec<Constant>,
    pub functions: Vec<Function>,
}

impl Namespace {
    fn new(name: &str) -> Namespace {
        Namespace {
            name: name.into(),
            types: Vec::new(),
            index: HashMap::new(),
            constants: Vec::new(),
            functions: Vec::new(),
        }
    }

    fn add_constant(&mut self, c: Constant) {
        self.constants.push(c);
    }

    fn add_function(&mut self, f: Function) {
        self.functions.push(f);
    }

    fn type_(&self, id: u32) -> &Type {
        self.types[id as usize].as_ref().unwrap()
    }

    fn type_mut(&mut self, id: u32) -> &mut Type {
        self.types[id as usize].as_mut().unwrap()
    }

    fn add_type(&mut self, name: &str, typ: Option<Type>) -> u32 {
        if let Some(id) = self.find_type(name) {
            self.types[id as usize] = typ;
            id
        }
        else {
            let id = self.types.len() as u32;
            self.types.push(typ);
            self.index.insert(name.into(), id);
            id
        }
    }

    fn find_type(&self, name: &str) -> Option<u32> {
        self.index.get(name).cloned()
    }

    fn unresolved(&self) -> Vec<&str> {
        self.index.iter().filter_map(|(name, &id)| {
            if self.types[id as usize].is_none() {
                Some(&name[..])
            } else {
                None
            }
        }).collect()
    }
}

pub const INTERNAL_NAMESPACE_NAME: &'static str = "*";
pub const INTERNAL_NAMESPACE: u16 = 0;

pub struct Library {
    pub namespaces: Vec<Namespace>,
    pub index: HashMap<String, u16>,
}

impl Library {
    pub fn new() -> Library {
        let mut library = Library {
            namespaces: Vec::new(),
            index: HashMap::new(),
        };
        assert!(library.add_namespace(INTERNAL_NAMESPACE_NAME) == INTERNAL_NAMESPACE);
        library.namespace_mut(INTERNAL_NAMESPACE).name = INTERNAL_NAMESPACE_NAME.into();
        for &(name, t) in &FUNDAMENTAL {
            library.add_type(INTERNAL_NAMESPACE, name, Type::Fundamental(t));
        }
        library
    }

    pub fn namespace(&self, ns_id: u16) -> &Namespace {
        &self.namespaces[ns_id as usize]
    }

    pub fn namespace_mut(&mut self, ns_id: u16) -> &mut Namespace {
        &mut self.namespaces[ns_id as usize]
    }

    pub fn find_namespace(&self, name: &str) -> Option<u16> {
        self.index.get(name).cloned()
    }

    pub fn add_namespace(&mut self, name: &str) -> u16 {
        if let Some(&id) = self.index.get(name) {
            id
        }
        else {
            let id = self.namespaces.len() as u16;
            self.namespaces.push(Namespace::new(name));
            self.index.insert(name.into(), id);
            id
        }
    }

    pub fn add_constant(&mut self, ns_id: u16, c: Constant) {
        self.namespace_mut(ns_id).add_constant(c);
    }

    pub fn add_function(&mut self, ns_id: u16, f: Function) {
        self.namespace_mut(ns_id).add_function(f);
    }

    pub fn add_type(&mut self, ns_id: u16, name: &str, typ: Type) -> TypeId {
        TypeId { ns_id: ns_id, id: self.namespace_mut(ns_id).add_type(name, Some(typ)) }
    }

    pub fn find_type(&self, current_ns_id: u16, name: &str) -> Option<TypeId> {
        let (ns, name) = split_ns_name(name);

        if let Some(ns) = ns {
            self.find_namespace(ns).and_then(|ns_id| {
                self.namespace(ns_id).find_type(name).map(|id| TypeId { ns_id: ns_id, id: id })
            })
        }
        else if let Some(id) = self.namespace(current_ns_id).find_type(name) {
            Some(TypeId { ns_id: current_ns_id, id: id })
        }
        else if let Some(id) = self.namespace(INTERNAL_NAMESPACE).find_type(name) {
            Some(TypeId { ns_id: INTERNAL_NAMESPACE, id: id })
        }
        else {
            None
        }
    }

    pub fn find_or_stub_type(&mut self, current_ns_id: u16, name: &str) -> TypeId {
        if let Some(tid) = self.find_type(current_ns_id, name) {
            return tid;
        }

        let (ns, name) = split_ns_name(name);

        if let Some(ns) = ns {
            let ns_id = self.find_namespace(ns).unwrap_or_else(|| self.add_namespace(ns));
            let ns = self.namespace_mut(ns_id);
            let id = ns.find_type(name).unwrap_or_else(|| ns.add_type(name, None));
            return TypeId { ns_id: ns_id, id: id };
        }

        let id = self.namespace_mut(current_ns_id).add_type(name, None);
        TypeId { ns_id: current_ns_id, id: id }
    }

    pub fn type_(&self, tid: TypeId) -> &Type {
        self.namespace(tid.ns_id).type_(tid.id)
    }

    pub fn type_mut(&mut self, tid: TypeId) -> &Type {
        self.namespace_mut(tid.ns_id).type_mut(tid.id)
    }

    pub fn check_resolved(&self) {
        let list: Vec<_> = self.index.iter().flat_map(|(name, &id)| {
            let name = name.clone();
            self.namespace(id).unresolved().into_iter().map(move |s| format!("{}.{}", name, s))
        }).collect();

        if !list.is_empty() {
            panic!("Incomplete library, unresolved: {:?}", list);
        }
    }
}

fn split_ns_name(name: &str) -> (Option<&str>, &str) {
    let mut parts = name.split('.');
    let name = parts.next_back().unwrap();
    let ns = parts.next_back();
    assert!(ns.is_none() || parts.next().is_none());
    (ns, name)
}
<|endoftext|>


<commit_before>//! To synchronize start up of threads with
use std::{
    sync::mpsc::{channel, Receiver, Sender},
    time::Duration,
};

const THREAD_SYNC_TIMEOUT: Duration = Duration::from_millis(100);

pub enum Process {
    Go,
}
pub enum SyncStartUp {
    SendReceiver(Sender<Process>),
    NoWait,
}

/// StartUp is a module with just methods, no data
/// to simplify sub-threads to main thread synchronization
/// by basically using a channel with a back message.
///
/// The idea is that threads start unordered to a certain
/// point when they can assure that they from this point on
/// are ready for going forward (e.g. listening for other
/// channel messages) and are blocked until the main thread
/// commands a go.
/// Here it is that main thread waits for 2 threads to get
/// ready and then main thread sends based on that a go
/// for the thread.
pub struct StartUp {}

impl StartUp {
    /// Blocks until channel counterpart receiver gives an ok.
    ///
    /// # Arguments
    ///
    /// * `ready_sender` - The sender of the channel which the main thread listens on
    /// * `name` - A string slice that holds the name of the person
    pub fn block_on_sync(ready_sender: Sender<SyncStartUp>, name: &str) {
        let (ready_sync_sender_from, ready_sync_receiver_from) = channel::<Process>();
        ready_sender
            .send(SyncStartUp::SendReceiver(ready_sync_sender_from))
            .expect(&["collection from ui receiver for", name, "not yet there???"].join(" "));
        trace!("sending out to sync ui start for {:?}", name);
        ready_sync_receiver_from
            .recv_timeout(THREAD_SYNC_TIMEOUT)
            .expect(&["the ui channel for", name, "was just sent?"].join(" "));
        trace!("sync ui start received for {:?}", name);
    }

    // todo: timeout and results should be considered!!! a little panicking maybe
    pub fn send_and_block2(
        ready_1st_receiver: &Receiver<SyncStartUp>,
        ready_2nd_receiver: &Receiver<SyncStartUp>,
    ) {
        // a yet not so nice implementation of select! for 2 threads
        loop {
            if Self::timeout_try_2_receiver((ready_1st_receiver, ready_2nd_receiver)) {
                break;
            } else {
                if Self::timeout_try_2_receiver((ready_2nd_receiver, &ready_1st_receiver)) {
                    break;
                }
            }
        }
    }

    // todo: timeout and results should be considered!!! a little panicking maybe
    fn send_back_return(all: Vec<&SyncStartUp>) {
        for el in all {
            match el {
                SyncStartUp::SendReceiver(sender) => {
                    sender
                        .send(Process::Go)
                        .expect("there has to be a receiver, the sender was sent here!");
                }
                SyncStartUp::NoWait => {}
            }
        }
    }

    fn timeout_try_2_receiver((a, b): (&Receiver<SyncStartUp>, &Receiver<SyncStartUp>)) -> bool {
        if let Ok(try_receiver1) = a.try_recv() {
            trace!("sync with 1st worked");
            b.recv_timeout(THREAD_SYNC_TIMEOUT)
                .and_then(|in_time_receiver2| {
                    trace!("sync with 2nd worked");
                    Self::send_back_return(vec![&try_receiver1, &in_time_receiver2]);
                    Ok(true)
                })
                .unwrap_or(false)
        } else {
            false
        }
    }
}
<commit_msg>[webui] testing timeouts for startup sync, since browser plus js answer needs time, suspend longer<commit_after>//! To synchronize start up of threads with
use std::{
    sync::mpsc::{channel, Receiver, Sender},
    time::Duration,
};

const THREAD_SYNC_TIMEOUT: Duration = Duration::from_millis(1000);

pub enum Process {
    Go,
}
pub enum SyncStartUp {
    SendReceiver(Sender<Process>),
    NoWait,
}

/// StartUp is a module with just methods, no data
/// to simplify sub-threads to main thread synchronization
/// by basically using a channel with a back message.
///
/// The idea is that threads start unordered to a certain
/// point when they can assure that they from this point on
/// are ready for going forward (e.g. listening for other
/// channel messages) and are blocked until the main thread
/// commands a go.
/// Here it is that main thread waits for 2 threads to get
/// ready and then main thread sends based on that a go
/// for the thread.
pub struct StartUp {}

impl StartUp {
    /// Blocks until channel counterpart receiver gives an ok.
    ///
    /// # Arguments
    ///
    /// * `ready_sender` - The sender of the channel which the main thread listens on
    /// * `name` - A string slice that holds the name of the person
    pub fn block_on_sync(ready_sender: Sender<SyncStartUp>, name: &str) {
        let (ready_sync_sender_from, ready_sync_receiver_from) = channel::<Process>();
        ready_sender
            .send(SyncStartUp::SendReceiver(ready_sync_sender_from))
            .expect(&["collection from ui receiver for", name, "not yet there???"].join(" "));
        trace!("sending out to sync ui start for {:?}", name);
        ready_sync_receiver_from
            .recv_timeout(THREAD_SYNC_TIMEOUT)
            .expect(&["the ui channel for", name, "was just sent?"].join(" "));
        trace!("sync ui start received for {:?}", name);
    }

    // todo: timeout and results should be considered!!! a little panicking maybe
    pub fn send_and_block2(
        ready_1st_receiver: &Receiver<SyncStartUp>,
        ready_2nd_receiver: &Receiver<SyncStartUp>,
    ) {
        // a yet not so nice implementation of select! for 2 threads
        loop {
            if Self::timeout_try_2_receiver((ready_1st_receiver, ready_2nd_receiver)) {
                break;
            } else {
                if Self::timeout_try_2_receiver((ready_2nd_receiver, &ready_1st_receiver)) {
                    break;
                }
            }
        }
    }

    // todo: timeout and results should be considered!!! a little panicking maybe
    fn send_back_return(all: Vec<&SyncStartUp>) {
        for el in all {
            match el {
                SyncStartUp::SendReceiver(sender) => {
                    sender
                        .send(Process::Go)
                        .expect("there has to be a receiver, the sender was sent here!");
                }
                SyncStartUp::NoWait => {}
            }
        }
    }

    fn timeout_try_2_receiver((a, b): (&Receiver<SyncStartUp>, &Receiver<SyncStartUp>)) -> bool {
        if let Ok(try_receiver1) = a.try_recv() {
            trace!("sync with 1st worked");
            b.recv_timeout(THREAD_SYNC_TIMEOUT)
                .and_then(|in_time_receiver2| {
                    trace!("sync with 2nd worked");
                    Self::send_back_return(vec![&try_receiver1, &in_time_receiver2]);
                    Ok(true)
                })
                .unwrap_or(false)
        } else {
            false
        }
    }
}
<|endoftext|>