<commit_before>//! Support for mock HTTP servers that verify pacts.

use pact_matching::models::*;
use pact_mock_server::matching::MatchResult;
use pact_mock_server::*;
use std::{
    env,
    fmt::Write as FmtWrite,
    io::{self, prelude::*},
    thread,
};
use url::Url;
use pact_mock_server::mock_server::MockServerConfig;
use std::cell::RefCell;
use std::sync::{Mutex, Arc};

/// This trait is implemented by types which allow us to start a mock server.
pub trait StartMockServer {
    /// Start a mock server running in a background thread.
    fn start_mock_server(&self) -> ValidatingMockServer;
}

impl StartMockServer for RequestResponsePact {
    fn start_mock_server(&self) -> ValidatingMockServer {
        ValidatingMockServer::start(self.clone())
    }
}

/// A mock HTTP server that handles the requests described in a `Pact`, intended
/// for use in tests, and validates that the requests made to that server are
/// correct.
///
/// Because this is intended for use in tests, it will panic if something goes
/// wrong.
pub struct ValidatingMockServer {
    // A description of our mock server, for use in error messages.
    description: String,
    // The URL of our mock server.
    url: Url,
    // The mock server instance
    mock_server: Arc<Mutex<mock_server::MockServer>>,
    // Signal received when the server thread is done executing
    done_rx: std::sync::mpsc::Receiver<()>,
}

impl ValidatingMockServer {
    /// Create a new mock server which handles requests as described in the
    /// pact, and runs in a background thread
    pub fn start(pact: RequestResponsePact) -> ValidatingMockServer {
        // Spawn new runtime in thread to prevent reactor execution context conflict
        let (mock_server, done_rx) = std::thread::spawn(move || {
            let mut runtime = tokio::runtime::Builder::new()
                .basic_scheduler()
                .enable_all()
                .build()
                .expect("new runtime");

            let (mock_server, server_future) = runtime.block_on(async move {
              mock_server::MockServer::new("".into(), pact, ([0, 0, 0, 0], 0 as u16).into(),
                MockServerConfig::default())
                .await
                .unwrap()
            });

            // Start the actual thread the runtime will run on
            let (done_tx, done_rx) = std::sync::mpsc::channel::<()>();
            let tname = format!(
                "test({})-pact-mock-server",
                thread::current().name().unwrap_or("<unknown>")
            );
            std::thread::Builder::new()
                .name(tname)
                .spawn(move || {
                    runtime.block_on(server_future);
                    let _ = done_tx.send(());
                })
                .expect("thread spawn");

            (mock_server, done_rx)
        })
        .join()
        .unwrap();

        let (description, url_str) = {
          let ms = mock_server.lock().unwrap();
          let description = format!(
            "{}/{}", ms.pact.consumer.name, ms.pact.provider.name
          );
          (description, ms.url())
        };
        ValidatingMockServer {
          description,
          url: url_str.parse().expect("invalid mock server URL"),
          mock_server,
          done_rx,
        }
    }

    /// The URL of our mock server. You can make normal HTTP requests using this
    /// as the base URL.
    pub fn url(&self) -> &Url {
        &self.url
    }

    /// Given a path string, return a URL pointing to that path on the mock
    /// server. If the `path` cannot be parsed as URL, **this function will
    /// panic**. For a non-panicking version, call `.url()` instead and build
    /// this path yourself.
    pub fn path<P: AsRef<str>>(&self, path: P) -> Url {
        // We panic here because this a _test_ library, the `?` operator is
        // useless in tests, and filling up our test code with piles of `unwrap`
        // calls is ugly.
        self.url.join(path.as_ref()).expect("could not parse URL")
    }

    /// Returns the current status of the mock server
    pub fn status(&self) -> Vec<MatchResult> {
      self.mock_server.lock().unwrap().mismatches()
    }

    /// Helper function called by our `drop` implementation. This basically exists
    /// so that it can return `Err(message)` whenever needed without making the
    /// flow control in `drop` ultra-complex.
    fn drop_helper(&mut self) -> Result<(), String> {
        // Kill the server
        let mut ms = self.mock_server.lock().unwrap();
        ms.shutdown()?;

        if ::std::thread::panicking() {
            return Ok(());
        }

        // Wait for the server thread to finish
        self.done_rx
            .recv_timeout(std::time::Duration::from_secs(3))
            .expect("mock server thread should not panic");

        // Look up any mismatches which occurred.
        let mismatches = ms.mismatches();

        if mismatches.is_empty() {
            // Success! Write out the generated pact file.
            ms.write_pact(&Some(
                env::var("PACT_OUTPUT_DIR").unwrap_or_else(|_| "target/pacts".to_owned()),
            ))
            .map_err(|err| format!("error writing pact: {}", err))?;
            Ok(())
        } else {
            // Failure. Format our errors.
            let mut msg = format!("mock server {} failed verification:\n", self.description,);
            for mismatch in mismatches {
                match mismatch {
                    MatchResult::RequestMatch(_) => {
                        unreachable!("list of mismatches contains a match");
                    }
                    MatchResult::RequestMismatch(interaction, mismatches) => {
                        let _ = writeln!(&mut msg, "- interaction {:?}:", interaction.description,);
                        for m in mismatches {
                            let _ = writeln!(&mut msg, "  - {}", m.description());
                        }
                    }
                    MatchResult::RequestNotFound(request) => {
                        let _ = writeln!(&mut msg, "- received unexpected request:");
                        let _ = writeln!(&mut msg, "{:#?}", request);
                    }
                    MatchResult::MissingRequest(interaction) => {
                        let _ = writeln!(
                            &mut msg,
                            "- interaction {:?} expected, but never occurred",
                            interaction.description,
                        );
                        let _ = writeln!(&mut msg, "{:#?}", interaction.request);
                    }
                }
            }
            Err(msg)
        }
    }
}

/// Either panic with `msg`, or if we're already in the middle of a panic,
/// just print `msg` to standard error.
fn panic_or_print_error(msg: &str) {
    if thread::panicking() {
        // The current thread is panicking, so don't try to panic again, because
        // double panics don't print useful explanations of why the test failed.
        // Instead, just print to `stderr`. Ignore any errors, because there's
        // not much we can do if we can't panic and we can't write to `stderr`.
        let _ = writeln!(io::stderr(), "{}", msg);
    } else {
        panic!("{}", msg);
    }
}

impl Drop for ValidatingMockServer {
    fn drop(&mut self) {
        let result = self.drop_helper();
        if let Err(msg) = result {
            panic_or_print_error(&msg);
        }
    }
}
<commit_msg>fix: cleanup compiler warning<commit_after>//! Support for mock HTTP servers that verify pacts.

use pact_matching::models::*;
use pact_mock_server::matching::MatchResult;
use pact_mock_server::*;
use std::{
    env,
    fmt::Write as FmtWrite,
    io::{self, prelude::*},
    thread,
};
use url::Url;
use pact_mock_server::mock_server::MockServerConfig;
use std::sync::{Mutex, Arc};

/// This trait is implemented by types which allow us to start a mock server.
pub trait StartMockServer {
    /// Start a mock server running in a background thread.
    fn start_mock_server(&self) -> ValidatingMockServer;
}

impl StartMockServer for RequestResponsePact {
    fn start_mock_server(&self) -> ValidatingMockServer {
        ValidatingMockServer::start(self.clone())
    }
}

/// A mock HTTP server that handles the requests described in a `Pact`, intended
/// for use in tests, and validates that the requests made to that server are
/// correct.
///
/// Because this is intended for use in tests, it will panic if something goes
/// wrong.
pub struct ValidatingMockServer {
    // A description of our mock server, for use in error messages.
    description: String,
    // The URL of our mock server.
    url: Url,
    // The mock server instance
    mock_server: Arc<Mutex<mock_server::MockServer>>,
    // Signal received when the server thread is done executing
    done_rx: std::sync::mpsc::Receiver<()>,
}

impl ValidatingMockServer {
    /// Create a new mock server which handles requests as described in the
    /// pact, and runs in a background thread
    pub fn start(pact: RequestResponsePact) -> ValidatingMockServer {
        // Spawn new runtime in thread to prevent reactor execution context conflict
        let (mock_server, done_rx) = std::thread::spawn(move || {
            let mut runtime = tokio::runtime::Builder::new()
                .basic_scheduler()
                .enable_all()
                .build()
                .expect("new runtime");

            let (mock_server, server_future) = runtime.block_on(async move {
              mock_server::MockServer::new("".into(), pact, ([0, 0, 0, 0], 0 as u16).into(),
                MockServerConfig::default())
                .await
                .unwrap()
            });

            // Start the actual thread the runtime will run on
            let (done_tx, done_rx) = std::sync::mpsc::channel::<()>();
            let tname = format!(
                "test({})-pact-mock-server",
                thread::current().name().unwrap_or("<unknown>")
            );
            std::thread::Builder::new()
                .name(tname)
                .spawn(move || {
                    runtime.block_on(server_future);
                    let _ = done_tx.send(());
                })
                .expect("thread spawn");

            (mock_server, done_rx)
        })
        .join()
        .unwrap();

        let (description, url_str) = {
          let ms = mock_server.lock().unwrap();
          let description = format!(
            "{}/{}", ms.pact.consumer.name, ms.pact.provider.name
          );
          (description, ms.url())
        };
        ValidatingMockServer {
          description,
          url: url_str.parse().expect("invalid mock server URL"),
          mock_server,
          done_rx,
        }
    }

    /// The URL of our mock server. You can make normal HTTP requests using this
    /// as the base URL.
    pub fn url(&self) -> &Url {
        &self.url
    }

    /// Given a path string, return a URL pointing to that path on the mock
    /// server. If the `path` cannot be parsed as URL, **this function will
    /// panic**. For a non-panicking version, call `.url()` instead and build
    /// this path yourself.
    pub fn path<P: AsRef<str>>(&self, path: P) -> Url {
        // We panic here because this a _test_ library, the `?` operator is
        // useless in tests, and filling up our test code with piles of `unwrap`
        // calls is ugly.
        self.url.join(path.as_ref()).expect("could not parse URL")
    }

    /// Returns the current status of the mock server
    pub fn status(&self) -> Vec<MatchResult> {
      self.mock_server.lock().unwrap().mismatches()
    }

    /// Helper function called by our `drop` implementation. This basically exists
    /// so that it can return `Err(message)` whenever needed without making the
    /// flow control in `drop` ultra-complex.
    fn drop_helper(&mut self) -> Result<(), String> {
        // Kill the server
        let mut ms = self.mock_server.lock().unwrap();
        ms.shutdown()?;

        if ::std::thread::panicking() {
            return Ok(());
        }

        // Wait for the server thread to finish
        self.done_rx
            .recv_timeout(std::time::Duration::from_secs(3))
            .expect("mock server thread should not panic");

        // Look up any mismatches which occurred.
        let mismatches = ms.mismatches();

        if mismatches.is_empty() {
            // Success! Write out the generated pact file.
            ms.write_pact(&Some(
                env::var("PACT_OUTPUT_DIR").unwrap_or_else(|_| "target/pacts".to_owned()),
            ))
            .map_err(|err| format!("error writing pact: {}", err))?;
            Ok(())
        } else {
            // Failure. Format our errors.
            let mut msg = format!("mock server {} failed verification:\n", self.description,);
            for mismatch in mismatches {
                match mismatch {
                    MatchResult::RequestMatch(_) => {
                        unreachable!("list of mismatches contains a match");
                    }
                    MatchResult::RequestMismatch(interaction, mismatches) => {
                        let _ = writeln!(&mut msg, "- interaction {:?}:", interaction.description,);
                        for m in mismatches {
                            let _ = writeln!(&mut msg, "  - {}", m.description());
                        }
                    }
                    MatchResult::RequestNotFound(request) => {
                        let _ = writeln!(&mut msg, "- received unexpected request:");
                        let _ = writeln!(&mut msg, "{:#?}", request);
                    }
                    MatchResult::MissingRequest(interaction) => {
                        let _ = writeln!(
                            &mut msg,
                            "- interaction {:?} expected, but never occurred",
                            interaction.description,
                        );
                        let _ = writeln!(&mut msg, "{:#?}", interaction.request);
                    }
                }
            }
            Err(msg)
        }
    }
}

/// Either panic with `msg`, or if we're already in the middle of a panic,
/// just print `msg` to standard error.
fn panic_or_print_error(msg: &str) {
    if thread::panicking() {
        // The current thread is panicking, so don't try to panic again, because
        // double panics don't print useful explanations of why the test failed.
        // Instead, just print to `stderr`. Ignore any errors, because there's
        // not much we can do if we can't panic and we can't write to `stderr`.
        let _ = writeln!(io::stderr(), "{}", msg);
    } else {
        panic!("{}", msg);
    }
}

impl Drop for ValidatingMockServer {
    fn drop(&mut self) {
        let result = self.drop_helper();
        if let Err(msg) = result {
            panic_or_print_error(&msg);
        }
    }
}
<|endoftext|>


<commit_before>use rusqlite::Connection;
use std::result;

#[derive(Debug)]
pub struct VariablePair {
    id: i32,
    fk_variable: i32,
    variable_value: String
}

pub fn table_create_variable_pair(conn: &Connection) {
    let load_table = conn.execute("CREATE TABLE  VARIABLE_PAIR (
                  id            INTEGER PRIMARY KEY ASC,
                  fk_variable   INTEGER NOT NULL,
                  variable_value  TEXT,
                  FOREIGN KEY(fk_variable) REFERENCES VARIABLE_NAME(id) ON UPDATE CASCADE
                  )", &[]);
    if load_table.is_err() {
        println!("table_create_job Failed {:?}", load_table);
        return;
    }
    load_table.unwrap();
}

pub fn insert_variable_pair(conn: &Connection, fk_variable :&i32, name: &String) -> Result<i32, &'static str> {
    let bill = fk_variable;
    let me = VariablePair {
        id : 0,
        fk_variable: bill.clone(),
        variable_value: name.clone(),
    };
    let variable_pair_instance = conn.execute("INSERT INTO VARIABLE_PAIR (fk_variable, variable_value)
                  VALUES (?1 ?2)",
                 &[&me.fk_variable, &me.variable_value]);
    if variable_pair_instance.is_err() {
        return Err("Insert failed");
    }
    variable_pair_instance.unwrap();
    return Ok(0);
}

pub fn list_variable_pair(conn: &Connection)-> Vec<VariablePair> {
    let mut stmt = conn.prepare("SELECT id, fk_variable, variable_value  FROM VARIABLE_PAIR").unwrap();
    let wraped_fs_file_iter = stmt.query_map(&[], |row| {
        VariablePair {
            id: row.get(0),
            fk_variable: row.get(1),
            variable_value: row.get(2),
        }
    });
    let mut items = Vec::<VariablePair>::new();
    if wraped_fs_file_iter.is_err() {
        return items;

    }
    let fs_file_iter = wraped_fs_file_iter.unwrap();
    for person in fs_file_iter {

        items.push(person.unwrap());
    }
    return items;
}

pub fn variable_pair_list(conn: &Connection) {
    let mut stmt = conn.prepare("SELECT id, fk_variable, variable_value FROM VARIABLE_PAIR").unwrap();
    let person_iter = stmt.query_map(&[], |row| {
        VariablePair {
            id: row.get(0),
            fk_variable: row.get(1),
            variable_value: row.get(2),
        }
    }).unwrap();

    for person in person_iter {
        println!("Found variable_pair {:?}", person.unwrap());
    }
}

pub fn pk_variable_pair_by_name(conn: &Connection, fk_variable :&i32, name: &str) -> Result<i32, &'static str>{
    let mut output = 0;
    let bill = String::from(name);
    let mut stmt = conn.prepare("SELECT VARIABLE_PAIR.id, VARIABLE_PAIR.fk_variable, VARIABLE_PAIR.variable_value  FROM VARIABLE_PAIR
		WHERE VARIABLE_PAIR.fk_variable = ?1 AND VARIABLE_PAIR.variable_value = ?2").unwrap();
    let variable_pair_iter = stmt.query_map(&[fk_variable,&bill], |row| {
        VariablePair {
            id: row.get(0),
            fk_variable: row.get(1),
            variable_value: row.get(2),
        }
    });
    if variable_pair_iter.is_err() {
        return Err("Insert failed dfdf");
    }
    let result = variable_pair_iter.unwrap();
    let mut found = 0;
    let mut items = Vec::<i32>::new();
    for person in result {
        let bill= person.unwrap();
        output = bill.id;
        found = 1;
    }
    if found != 0 {
        return Ok(output);
    }
    return Err("None found");
}
<commit_msg>Improve referance handling<commit_after>use rusqlite::Connection;
use std::result;

#[derive(Debug)]
pub struct VariablePair {
    id: i32,
    fk_variable: i32,
    variable_value: String
}

pub fn table_create_variable_pair(conn: &Connection) {
    let load_table = conn.execute("CREATE TABLE  VARIABLE_PAIR (
                  id            INTEGER PRIMARY KEY ASC,
                  fk_variable   INTEGER NOT NULL,
                  variable_value  TEXT,
                  FOREIGN KEY(fk_variable) REFERENCES VARIABLE_NAME(id) ON UPDATE CASCADE
                  )", &[]);
    if load_table.is_err() {
        println!("table_create_job Failed {:?}", load_table);
        return;
    }
    load_table.unwrap();
}

pub fn insert_variable_pair(conn: &Connection, fk_variable :&i32, name: &str) -> Result<i32, &'static str> {
    let bill = fk_variable;
    let mut john = String::from(name);
    let me = VariablePair {
        id : 0,
        fk_variable: bill.clone(),
        variable_value: john,
    };
    let variable_pair_instance = conn.execute("INSERT INTO VARIABLE_PAIR (fk_variable, variable_value)
                  VALUES (?1 ?2)",
                 &[&me.fk_variable, &me.variable_value]);
    if variable_pair_instance.is_err() {
        return Err("Insert failed");
    }
    variable_pair_instance.unwrap();
    return Ok(0);
}

pub fn list_variable_pair(conn: &Connection)-> Vec<VariablePair> {
    let mut stmt = conn.prepare("SELECT id, fk_variable, variable_value  FROM VARIABLE_PAIR").unwrap();
    let wraped_fs_file_iter = stmt.query_map(&[], |row| {
        VariablePair {
            id: row.get(0),
            fk_variable: row.get(1),
            variable_value: row.get(2),
        }
    });
    let mut items = Vec::<VariablePair>::new();
    if wraped_fs_file_iter.is_err() {
        return items;

    }
    let fs_file_iter = wraped_fs_file_iter.unwrap();
    for person in fs_file_iter {

        items.push(person.unwrap());
    }
    return items;
}

pub fn variable_pair_list(conn: &Connection) {
    let mut stmt = conn.prepare("SELECT id, fk_variable, variable_value FROM VARIABLE_PAIR").unwrap();
    let person_iter = stmt.query_map(&[], |row| {
        VariablePair {
            id: row.get(0),
            fk_variable: row.get(1),
            variable_value: row.get(2),
        }
    }).unwrap();

    for person in person_iter {
        println!("Found variable_pair {:?}", person.unwrap());
    }
}

pub fn pk_variable_pair_by_name(conn: &Connection, fk_variable :&i32, name: &str) -> Result<i32, &'static str>{
    let mut output = 0;
    let bill = String::from(name);
    let mut stmt = conn.prepare("SELECT VARIABLE_PAIR.id, VARIABLE_PAIR.fk_variable, VARIABLE_PAIR.variable_value  FROM VARIABLE_PAIR
		WHERE VARIABLE_PAIR.fk_variable = ?1 AND VARIABLE_PAIR.variable_value = ?2").unwrap();
    let variable_pair_iter = stmt.query_map(&[fk_variable,&bill], |row| {
        VariablePair {
            id: row.get(0),
            fk_variable: row.get(1),
            variable_value: row.get(2),
        }
    });
    if variable_pair_iter.is_err() {
        return Err("Insert failed dfdf");
    }
    let result = variable_pair_iter.unwrap();
    let mut found = 0;
    let mut items = Vec::<i32>::new();
    for person in result {
        let bill= person.unwrap();
        output = bill.id;
        found = 1;
    }
    if found != 0 {
        return Ok(output);
    }
    return Err("None found");
}
<|endoftext|>


<commit_before>// Copyright (C) 2015  Jonas Pollok <jonas.p@gmail.com>

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use std::fmt;
use std::str::FromStr;

use matching::Match;
use binding::Bind;

mod parser;

// TODO: implement equality check
/// The `Expression` type.
#[unstable(feature = "ers1")]
pub enum Expression {
    /// Contains a boxed slice of `Expressions`
    List(Vec<Expression>),
    /// Represents a string expression
    Atom(String),
    /// An unnamed pattern matching a single expression
    Blank,
    /// An unnamed pattern matching one or more expressions
    BlankSeq,
    /// An unnamed pattern matching zero or more expressions
    BlankNullSeq,
    /// A named pattern matching a single expression
    Pattern(String),
    /// A named pattern matching one or more expressions
    PatternSeq(String),
    /// A named pattern matching zero or more expressions
    PatternNullSeq(String),
}

#[unstable(feature = "ers1")]
impl Expression {
    /// Matches the `Expression` with a pattern and if successful binds returns
    /// the bound template.
    ///
    /// # Example
    /// ```
    /// use ers::Expression;
    ///
    /// let expr = "(x z)".parse::<Expression>().unwrap();
    /// let pattern = "(x a_)".parse::<Expression>().unwrap();
    /// let template = "(y a)".parse::<Expression>().unwrap();
    ///
    /// expr.replace(&pattern, template).unwrap(); // => (y z)
    /// ```
    #[unstable(feature = "ers1")]
    pub fn replace(&self, pattern: &Expression, template: Expression) -> Option<Expression> {
        self.match_pattern(pattern).map(move |bs| template.bind(&bs))
    }

    /// Replaces all expressions and subexpressions with the provided pattern
    /// and replaces it by the bound template
    ///
    /// # Example
    /// ```
    /// use ers::Expression;
    ///
    /// let expr = "((x r) (x s))".parse::<Expression>().unwrap();
    /// let pattern = "(x a_)".parse::<Expression>().unwrap();
    /// let template = "(y a)".parse::<Expression>().unwrap();
    ///
    /// expr.replace_all(&pattern, template); // => ((y r) (y s))
    /// ```
    #[unstable(feature = "ers1")]
    pub fn replace_all(&self, pattern: &Expression, template: Expression) -> Expression {
        let (e, _) = self.replace_rec(pattern, template);
        e
    }

    /// Replaces all expressions and subexpression repeatedly until the
    /// expression does not change anymore.
    /// The hardcoded limit is 1000 repetitions. The function panics if the
    /// limit is reached.
    ///
    /// # Example
    /// ```
    /// use ers::Expression;
    ///
    /// let expr = "(x (x (x z)))".parse::<Expression>().unwrap();
    /// let pattern = "(x a_)".parse::<Expression>().unwrap();
    /// let template = "(y a)".parse::<Expression>().unwrap();
    ///
    /// expr.replace_repeated(&pattern, template); // => (y (y (y z)))
    /// ```
    #[unstable(feature = "experimental")]
    pub fn replace_repeated(&self, pattern: &Expression, template: Expression) -> Expression {
        // TODO: set limit as global constant
        let mut limit = 1000;
        let mut expr = self.clone();
        while limit >= 0 {
            limit -= 1;
            let (new_expr, replaced) = expr.replace_rec(pattern, template.clone());
            if !replaced {
                return new_expr;
            }
            expr = new_expr;
        }
        // TODO: panic might not be the right thing to do
        panic!("replacement limit reached!");
    }

    fn replace_rec(&self, pattern: &Expression, template: Expression) -> (Expression, bool) {
        match self.match_pattern(pattern) {
            None => {
                match self {
                    &Expression::List(ref es) => {
                        let mut v: Vec<Expression> = Vec::new();
                        let mut replaced = false;
                        for e in es {
                            let (new_e, r) = e.replace_rec(pattern, template.clone());
                            if r {
                                replaced = true;
                            }
                            v.push(new_e);
                        }
                        (Expression::List(v), replaced)
                    }
                    _ => (self.clone(), false) // not replaced
                }
            }
            Some(bs) => (template.bind(&bs), true) // replaced
        }
    }
}

impl Clone for Expression {
    fn clone(&self) -> Self {
        match self {
            &Expression::List(ref es) => {
                let mut v: Vec<Expression> = Vec::new();
                for e in es {
                    v.push(e.clone());
                }
                Expression::List(v)
            }
            &Expression::Atom(ref s) => {
                Expression::Atom(s.clone())
            }
            &Expression::Blank => {
                Expression::Blank
            }
            &Expression::BlankSeq => {
                Expression::BlankSeq
            }
            &Expression::BlankNullSeq => {
                Expression::BlankNullSeq
            }
            &Expression::Pattern(ref s) => {
                Expression::Pattern(s.clone())
            }
            &Expression::PatternSeq(ref s) => {
                Expression::PatternSeq(s.clone())
            }
            &Expression::PatternNullSeq(ref s) => {
                Expression::PatternNullSeq(s.clone())
            }
        }
    }
}

impl fmt::Debug for Expression {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Expression::Atom(ref s) => { write!(f, "{}", s) }
            Expression::List(ref es) => {
                let mut s = String::new();
                for i in (0..es.len()) {
                    let f = format!("{:?}", es[i]);
                    s = s + &f[];
                    if i != es.len() - 1 {
                        s.push(' ');
                    }
                }
                write!(f, "({})", s)
            }
            Expression::Blank => { write!(f, "_") }
            Expression::BlankSeq => { write!(f, "__") }
            Expression::BlankNullSeq => { write!(f, "___") }
            Expression::Pattern(ref s) => { write!(f, "{}_", s)}
            Expression::PatternSeq(ref s) => { write!(f, "{}__", s)}
            Expression::PatternNullSeq(ref s) => { write!(f, "{}___", s)}
        }
    }
}

impl FromStr for Expression {
    type Err = parser::ParserError;
    fn from_str(s: &str) -> Result<Expression, parser::ParserError> {
        let mut parser = parser::Parser::new(s.chars());

        parser.parse()
    }
}

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

    #[test]
    fn debug() {
        let a = Expression::Atom("a".to_string());
        let b = Expression::Atom("b".to_string());
        let c = Expression::Atom("c".to_string());
        let d = Expression::Atom("d".to_string());

        let ls = Expression::List(vec![c, d]);

        let expr = Expression::List(vec![a, b, ls]);

        assert_eq!(format!("{:?}", expr), "(a b (c d))");
    }

    #[test]
    fn parse() {
        let expr = "(a b (c d))".parse::<Expression>();
        assert_eq!(format!("{:?}", expr.unwrap()), "(a b (c d))");
    }

    #[test]
    fn replace() {
        let expr = "(x z)".parse::<Expression>().unwrap();
        let pattern = "(x a_)".parse::<Expression>().unwrap();
        let template = "(y a)".parse::<Expression>().unwrap();

        let res = expr.replace(&pattern, template).unwrap();

        assert_eq!(format!("{:?}", res), "(y z)");
    }

    #[test]
    fn replace_all() {
        let expr = "((x r) (x s))".parse::<Expression>().unwrap();
        let pattern = "(x a_)".parse::<Expression>().unwrap();
        let template = "(y a)".parse::<Expression>().unwrap();

        let res = expr.replace_all(&pattern, template);

        assert_eq!(format!("{:?}", res), "((y r) (y s))");
    }

    #[test]
    fn replace_repeated() {
        let expr = "(x (x (x z)))".parse::<Expression>().unwrap();
        let pattern = "(x a_)".parse::<Expression>().unwrap();
        let template = "(y a)".parse::<Expression>().unwrap();

        let res = expr.replace_repeated(&pattern, template);

        assert_eq!(format!("{:?}", res), "(y (y (y z)))");
    }
}
<commit_msg>update slice notation<commit_after>// Copyright (C) 2015  Jonas Pollok <jonas.p@gmail.com>

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use std::fmt;
use std::str::FromStr;

use matching::Match;
use binding::Bind;

mod parser;

// TODO: implement equality check
/// The `Expression` type.
#[unstable(feature = "ers1")]
pub enum Expression {
    /// Contains a boxed slice of `Expressions`
    List(Vec<Expression>),
    /// Represents a string expression
    Atom(String),
    /// An unnamed pattern matching a single expression
    Blank,
    /// An unnamed pattern matching one or more expressions
    BlankSeq,
    /// An unnamed pattern matching zero or more expressions
    BlankNullSeq,
    /// A named pattern matching a single expression
    Pattern(String),
    /// A named pattern matching one or more expressions
    PatternSeq(String),
    /// A named pattern matching zero or more expressions
    PatternNullSeq(String),
}

#[unstable(feature = "ers1")]
impl Expression {
    /// Matches the `Expression` with a pattern and if successful binds returns
    /// the bound template.
    ///
    /// # Example
    /// ```
    /// use ers::Expression;
    ///
    /// let expr = "(x z)".parse::<Expression>().unwrap();
    /// let pattern = "(x a_)".parse::<Expression>().unwrap();
    /// let template = "(y a)".parse::<Expression>().unwrap();
    ///
    /// expr.replace(&pattern, template).unwrap(); // => (y z)
    /// ```
    #[unstable(feature = "ers1")]
    pub fn replace(&self, pattern: &Expression, template: Expression) -> Option<Expression> {
        self.match_pattern(pattern).map(move |bs| template.bind(&bs))
    }

    /// Replaces all expressions and subexpressions with the provided pattern
    /// and replaces it by the bound template
    ///
    /// # Example
    /// ```
    /// use ers::Expression;
    ///
    /// let expr = "((x r) (x s))".parse::<Expression>().unwrap();
    /// let pattern = "(x a_)".parse::<Expression>().unwrap();
    /// let template = "(y a)".parse::<Expression>().unwrap();
    ///
    /// expr.replace_all(&pattern, template); // => ((y r) (y s))
    /// ```
    #[unstable(feature = "ers1")]
    pub fn replace_all(&self, pattern: &Expression, template: Expression) -> Expression {
        let (e, _) = self.replace_rec(pattern, template);
        e
    }

    /// Replaces all expressions and subexpression repeatedly until the
    /// expression does not change anymore.
    /// The hardcoded limit is 1000 repetitions. The function panics if the
    /// limit is reached.
    ///
    /// # Example
    /// ```
    /// use ers::Expression;
    ///
    /// let expr = "(x (x (x z)))".parse::<Expression>().unwrap();
    /// let pattern = "(x a_)".parse::<Expression>().unwrap();
    /// let template = "(y a)".parse::<Expression>().unwrap();
    ///
    /// expr.replace_repeated(&pattern, template); // => (y (y (y z)))
    /// ```
    #[unstable(feature = "experimental")]
    pub fn replace_repeated(&self, pattern: &Expression, template: Expression) -> Expression {
        // TODO: set limit as global constant
        let mut limit = 1000;
        let mut expr = self.clone();
        while limit >= 0 {
            limit -= 1;
            let (new_expr, replaced) = expr.replace_rec(pattern, template.clone());
            if !replaced {
                return new_expr;
            }
            expr = new_expr;
        }
        // TODO: panic might not be the right thing to do
        panic!("replacement limit reached!");
    }

    fn replace_rec(&self, pattern: &Expression, template: Expression) -> (Expression, bool) {
        match self.match_pattern(pattern) {
            None => {
                match self {
                    &Expression::List(ref es) => {
                        let mut v: Vec<Expression> = Vec::new();
                        let mut replaced = false;
                        for e in es {
                            let (new_e, r) = e.replace_rec(pattern, template.clone());
                            if r {
                                replaced = true;
                            }
                            v.push(new_e);
                        }
                        (Expression::List(v), replaced)
                    }
                    _ => (self.clone(), false) // not replaced
                }
            }
            Some(bs) => (template.bind(&bs), true) // replaced
        }
    }
}

impl Clone for Expression {
    fn clone(&self) -> Self {
        match self {
            &Expression::List(ref es) => {
                let mut v: Vec<Expression> = Vec::new();
                for e in es {
                    v.push(e.clone());
                }
                Expression::List(v)
            }
            &Expression::Atom(ref s) => {
                Expression::Atom(s.clone())
            }
            &Expression::Blank => {
                Expression::Blank
            }
            &Expression::BlankSeq => {
                Expression::BlankSeq
            }
            &Expression::BlankNullSeq => {
                Expression::BlankNullSeq
            }
            &Expression::Pattern(ref s) => {
                Expression::Pattern(s.clone())
            }
            &Expression::PatternSeq(ref s) => {
                Expression::PatternSeq(s.clone())
            }
            &Expression::PatternNullSeq(ref s) => {
                Expression::PatternNullSeq(s.clone())
            }
        }
    }
}

impl fmt::Debug for Expression {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Expression::Atom(ref s) => { write!(f, "{}", s) }
            Expression::List(ref es) => {
                let mut s = String::new();
                for i in (0..es.len()) {
                    let f = format!("{:?}", es[i]);
                    s = s + &f[..];
                    if i != es.len() - 1 {
                        s.push(' ');
                    }
                }
                write!(f, "({})", s)
            }
            Expression::Blank => { write!(f, "_") }
            Expression::BlankSeq => { write!(f, "__") }
            Expression::BlankNullSeq => { write!(f, "___") }
            Expression::Pattern(ref s) => { write!(f, "{}_", s)}
            Expression::PatternSeq(ref s) => { write!(f, "{}__", s)}
            Expression::PatternNullSeq(ref s) => { write!(f, "{}___", s)}
        }
    }
}

impl FromStr for Expression {
    type Err = parser::ParserError;
    fn from_str(s: &str) -> Result<Expression, parser::ParserError> {
        let mut parser = parser::Parser::new(s.chars());

        parser.parse()
    }
}

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

    #[test]
    fn debug() {
        let a = Expression::Atom("a".to_string());
        let b = Expression::Atom("b".to_string());
        let c = Expression::Atom("c".to_string());
        let d = Expression::Atom("d".to_string());

        let ls = Expression::List(vec![c, d]);

        let expr = Expression::List(vec![a, b, ls]);

        assert_eq!(format!("{:?}", expr), "(a b (c d))");
    }

    #[test]
    fn parse() {
        let expr = "(a b (c d))".parse::<Expression>();
        assert_eq!(format!("{:?}", expr.unwrap()), "(a b (c d))");
    }

    #[test]
    fn replace() {
        let expr = "(x z)".parse::<Expression>().unwrap();
        let pattern = "(x a_)".parse::<Expression>().unwrap();
        let template = "(y a)".parse::<Expression>().unwrap();

        let res = expr.replace(&pattern, template).unwrap();

        assert_eq!(format!("{:?}", res), "(y z)");
    }

    #[test]
    fn replace_all() {
        let expr = "((x r) (x s))".parse::<Expression>().unwrap();
        let pattern = "(x a_)".parse::<Expression>().unwrap();
        let template = "(y a)".parse::<Expression>().unwrap();

        let res = expr.replace_all(&pattern, template);

        assert_eq!(format!("{:?}", res), "((y r) (y s))");
    }

    #[test]
    fn replace_repeated() {
        let expr = "(x (x (x z)))".parse::<Expression>().unwrap();
        let pattern = "(x a_)".parse::<Expression>().unwrap();
        let template = "(y a)".parse::<Expression>().unwrap();

        let res = expr.replace_repeated(&pattern, template);

        assert_eq!(format!("{:?}", res), "(y (y (y z)))");
    }
}
<|endoftext|>


<commit_before>use parking_lot::MutexGuard;
use std::cmp;

use ctxt::VM;
use gc::root::Slot;
use gc::space::Space;
use gc::swiper::card::CardTable;
use gc::swiper::crossing::CrossingMap;
use gc::swiper::large::LargeSpace;
use gc::swiper::old::{OldGen, OldGenProtected};
use gc::swiper::young::YoungGen;
use gc::{Address, GcReason, Region};
use object::Obj;

pub struct FullCollector<'a, 'ast: 'a> {
    vm: &'a VM<'ast>,
    heap: Region,
    young: &'a YoungGen,
    old: &'a OldGen,
    old_protected: MutexGuard<'a, OldGenProtected>,
    large_space: &'a LargeSpace,
    rootset: &'a [Slot],
    card_table: &'a CardTable,
    crossing_map: &'a CrossingMap,
    perm_space: &'a Space,

    old_top: Address,
    old_limit: Address,
    old_committed: Region,
    init_old_top: Vec<Address>,

    reason: GcReason,

    min_heap_size: usize,
    max_heap_size: usize,
}

impl<'a, 'ast> FullCollector<'a, 'ast> {
    pub fn new(
        vm: &'a VM<'ast>,
        heap: Region,
        young: &'a YoungGen,
        old: &'a OldGen,
        large_space: &'a LargeSpace,
        card_table: &'a CardTable,
        crossing_map: &'a CrossingMap,
        perm_space: &'a Space,
        rootset: &'a [Slot],
        reason: GcReason,
        min_heap_size: usize,
        max_heap_size: usize,
    ) -> FullCollector<'a, 'ast> {
        let old_total = old.total();

        FullCollector {
            vm: vm,
            heap: heap,
            young: young,
            old: old,
            old_protected: old.protected(),
            large_space: large_space,
            rootset: rootset,
            card_table: card_table,
            crossing_map: crossing_map,
            perm_space: perm_space,

            old_top: old_total.start,
            old_limit: old_total.end,
            old_committed: Default::default(),
            init_old_top: Vec::new(),

            reason: reason,

            min_heap_size: min_heap_size,
            max_heap_size: max_heap_size,
        }
    }

    pub fn collect(&mut self) {
        let dev_verbose = self.vm.args.flag_gc_dev_verbose;
        self.init_old_top = self.old_protected.regions.iter().map(|r| r.top()).collect();

        if dev_verbose {
            println!("Full GC: Phase 1 (marking)");
        }

        self.mark_live();

        if dev_verbose {
            println!("Full GC: Phase 2 (compute forward)");
        }

        self.compute_forward();

        if dev_verbose {
            println!("Full GC: Phase 3 (update refs)");
        }

        self.update_references();

        if dev_verbose {
            println!("Full GC: Phase 4 (relocate)");
        }

        self.relocate();

        if dev_verbose {
            println!("Full GC: Phase 5 (large objects)");
        }

        self.update_large_objects();

        if dev_verbose {
            println!("Full GC: Phase 5 (large objects) finished.");
        }

        self.reset_cards();

        self.young.clear();
        self.young.protect_to();

        self.old_protected.update_single_region(self.old_top);
    }

    fn mark_live(&mut self) {
        let mut marking_stack: Vec<Address> = Vec::new();

        for root in self.rootset {
            let root_ptr = root.get();

            if self.heap.contains(root_ptr) {
                let root_obj = root_ptr.to_mut_obj();

                if !root_obj.header().is_marked_non_atomic() {
                    marking_stack.push(root_ptr);
                    root_obj.header_mut().mark_non_atomic();
                }
            } else {
                debug_assert!(root_ptr.is_null() || self.perm_space.contains(root_ptr));
            }
        }

        while marking_stack.len() > 0 {
            let object_addr = marking_stack.pop().expect("stack already empty");
            let object = object_addr.to_mut_obj();

            object.visit_reference_fields(|field| {
                let field_addr = field.get();

                if self.heap.contains(field_addr) {
                    let field_obj = field_addr.to_mut_obj();

                    if !field_obj.header().is_marked_non_atomic() {
                        marking_stack.push(field_addr);
                        field_obj.header_mut().mark_non_atomic();
                    }
                } else {
                    debug_assert!(field_addr.is_null() || self.perm_space.contains(field_addr));
                }
            });
        }
    }

    fn compute_forward(&mut self) {
        self.walk_old_and_young(|full, object, _address, object_size| {
            if object.header().is_marked_non_atomic() {
                let fwd = full.allocate(object_size);
                object.header_mut().set_fwdptr_non_atomic(fwd);
            }
        });

        self.old_protected.commit_single_region(self.old_top);
        self.old_committed = Region::new(self.old.total_start(), self.old_top);
    }

    fn update_references(&mut self) {
        self.walk_old_and_young(|full, object, _address, _| {
            if object.header().is_marked_non_atomic() {
                object.visit_reference_fields(|field| {
                    full.forward_reference(field);
                });
            }
        });

        for root in self.rootset {
            self.forward_reference(*root);
        }

        self.large_space.visit_objects(|object_start| {
            let object = object_start.to_mut_obj();

            if object.header().is_marked_non_atomic() {
                object.visit_reference_fields(|field| {
                    self.forward_reference(field);
                });
            }
        });
    }

    fn relocate(&mut self) {
        self.crossing_map.set_first_object(0.into(), 0);

        self.walk_old_and_young(|full, object, address, object_size| {
            if object.header().is_marked_non_atomic() {
                // get new location
                let dest = object.header().fwdptr_non_atomic();
                debug_assert!(full.old_committed.contains(dest));

                // determine location after relocated object
                let next_dest = dest.offset(object_size);
                debug_assert!(full.old_committed.valid_top(next_dest));

                if address != dest {
                    object.copy_to(dest, object_size);
                }

                // unmark object for next collection
                let dest_obj = dest.to_mut_obj();
                dest_obj.header_mut().unmark_non_atomic();

                full.old
                    .update_crossing(dest, next_dest, dest_obj.is_array_ref());
            }
        });
    }

    fn update_large_objects(&mut self) {
        self.large_space.remove_objects(|object_start| {
            let object = object_start.to_mut_obj();

            // reset cards for object, also do this for dead objects
            // to reset card entries to clean.
            if object.is_array_ref() {
                let object_end = object_start.offset(object.size());
                self.card_table.reset_region(object_start, object_end);
            } else {
                self.card_table.reset_addr(object_start);
            }

            if !object.header().is_marked_non_atomic() {
                // object is unmarked -> free it
                return false;
            }

            // unmark object for next collection
            object.header_mut().unmark_non_atomic();

            // keep object
            true
        });
    }

    fn reset_cards(&mut self) {
        let regions = self
            .old_protected
            .regions
            .iter()
            .map(|r| (r.start(), r.top()))
            .collect::<Vec<_>>();

        for ((start, top), init_top) in regions.into_iter().zip(&self.init_old_top) {
            let top = cmp::max(top, *init_top);
            self.card_table.reset_region(start, top);
        }
    }

    fn forward_reference(&mut self, slot: Slot) {
        let object_addr = slot.get();

        if self.heap.contains(object_addr) {
            debug_assert!(object_addr.to_obj().header().is_marked_non_atomic());

            if self.large_space.contains(object_addr) {
                // large objects do not move in memory
                return;
            }

            let fwd_addr = object_addr.to_obj().header().fwdptr_non_atomic();
            debug_assert!(self.heap.contains(fwd_addr));
            slot.set(fwd_addr);
        } else {
            debug_assert!(object_addr.is_null() || self.perm_space.contains(object_addr));
        }
    }

    fn walk_old_and_young<F>(&mut self, mut fct: F)
    where
        F: FnMut(&mut FullCollector, &mut Obj, Address, usize),
    {
        let old_regions = self
            .old_protected
            .regions
            .iter()
            .map(|r| r.active_region())
            .collect::<Vec<_>>();

        for old_region in old_regions {
            self.walk_region(old_region.start, old_region.end, &mut fct);
        }

        let used_region = self.young.eden_active();
        self.walk_region(used_region.start, used_region.end, &mut fct);

        let used_region = self.young.from_active();
        self.walk_region(used_region.start, used_region.end, &mut fct);

        // This is a bit strange at first: to-space might not be empty,
        // after too many survivors in the minor GC of the young gen.
        let used_region = self.young.to_active();
        self.walk_region(used_region.start, used_region.end, &mut fct);
    }

    fn walk_region<F>(&mut self, start: Address, end: Address, fct: &mut F)
    where
        F: FnMut(&mut FullCollector, &mut Obj, Address, usize),
    {
        let mut scan = start;

        while scan < end {
            let object = scan.to_mut_obj();

            if object.header().vtblptr().is_null() {
                scan = scan.add_ptr(1);
                continue;
            }

            let object_size = object.size();

            fct(self, object, scan, object_size);

            scan = scan.offset(object_size);
        }
    }

    fn allocate(&mut self, object_size: usize) -> Address {
        let addr = self.old_top;
        let next = self.old_top.offset(object_size);

        if next <= self.old_limit {
            self.old_top = next;
            return addr;
        }

        panic!("FAIL: Not enough space for objects in old generation.");
    }
}
<commit_msg>full: add marking verifier<commit_after>use parking_lot::MutexGuard;
use std::cmp;

use ctxt::VM;
use gc::root::Slot;
use gc::space::Space;
use gc::swiper::card::CardTable;
use gc::swiper::crossing::CrossingMap;
use gc::swiper::large::LargeSpace;
use gc::swiper::old::{OldGen, OldGenProtected};
use gc::swiper::young::YoungGen;
use gc::{Address, GcReason, Region};
use object::Obj;

pub struct FullCollector<'a, 'ast: 'a> {
    vm: &'a VM<'ast>,
    heap: Region,
    young: &'a YoungGen,
    old: &'a OldGen,
    old_protected: MutexGuard<'a, OldGenProtected>,
    large_space: &'a LargeSpace,
    rootset: &'a [Slot],
    card_table: &'a CardTable,
    crossing_map: &'a CrossingMap,
    perm_space: &'a Space,

    old_top: Address,
    old_limit: Address,
    old_committed: Region,
    init_old_top: Vec<Address>,

    reason: GcReason,

    min_heap_size: usize,
    max_heap_size: usize,
}

impl<'a, 'ast> FullCollector<'a, 'ast> {
    pub fn new(
        vm: &'a VM<'ast>,
        heap: Region,
        young: &'a YoungGen,
        old: &'a OldGen,
        large_space: &'a LargeSpace,
        card_table: &'a CardTable,
        crossing_map: &'a CrossingMap,
        perm_space: &'a Space,
        rootset: &'a [Slot],
        reason: GcReason,
        min_heap_size: usize,
        max_heap_size: usize,
    ) -> FullCollector<'a, 'ast> {
        let old_total = old.total();

        FullCollector {
            vm: vm,
            heap: heap,
            young: young,
            old: old,
            old_protected: old.protected(),
            large_space: large_space,
            rootset: rootset,
            card_table: card_table,
            crossing_map: crossing_map,
            perm_space: perm_space,

            old_top: old_total.start,
            old_limit: old_total.end,
            old_committed: Default::default(),
            init_old_top: Vec::new(),

            reason: reason,

            min_heap_size: min_heap_size,
            max_heap_size: max_heap_size,
        }
    }

    pub fn collect(&mut self) {
        let dev_verbose = self.vm.args.flag_gc_dev_verbose;
        self.init_old_top = self.old_protected.regions.iter().map(|r| r.top()).collect();

        if dev_verbose {
            println!("Full GC: Phase 1 (marking)");
        }

        self.mark_live();

        if self.vm.args.flag_gc_verify {
            if dev_verbose {
                println!("Full GC: Phase 1 (verify marking start)");
            }

            self.verify_marking();

            if dev_verbose {
                println!("Full GC: Phase 1 (verify marking end)");
            }
        }

        if dev_verbose {
            println!("Full GC: Phase 2 (compute forward)");
        }

        self.compute_forward();

        if dev_verbose {
            println!("Full GC: Phase 3 (update refs)");
        }

        self.update_references();

        if dev_verbose {
            println!("Full GC: Phase 4 (relocate)");
        }

        self.relocate();

        if dev_verbose {
            println!("Full GC: Phase 5 (large objects)");
        }

        self.update_large_objects();

        if dev_verbose {
            println!("Full GC: Phase 5 (large objects) finished.");
        }

        self.reset_cards();

        self.young.clear();
        self.young.protect_to();

        self.old_protected.update_single_region(self.old_top);
    }

    fn mark_live(&mut self) {
        let mut marking_stack: Vec<Address> = Vec::new();

        for root in self.rootset {
            let root_ptr = root.get();

            if self.heap.contains(root_ptr) {
                let root_obj = root_ptr.to_mut_obj();

                if !root_obj.header().is_marked_non_atomic() {
                    marking_stack.push(root_ptr);
                    root_obj.header_mut().mark_non_atomic();
                }
            } else {
                debug_assert!(root_ptr.is_null() || self.perm_space.contains(root_ptr));
            }
        }

        while marking_stack.len() > 0 {
            let object_addr = marking_stack.pop().expect("stack already empty");
            let object = object_addr.to_mut_obj();

            object.visit_reference_fields(|field| {
                let field_addr = field.get();

                if self.heap.contains(field_addr) {
                    let field_obj = field_addr.to_mut_obj();

                    if !field_obj.header().is_marked_non_atomic() {
                        marking_stack.push(field_addr);
                        field_obj.header_mut().mark_non_atomic();
                    }
                } else {
                    debug_assert!(field_addr.is_null() || self.perm_space.contains(field_addr));
                }
            });
        }
    }

    fn verify_marking(&self) {
        for region in &self.old_protected.regions {
            let active = region.active_region();
            verify_marking_region(active, self.heap);
        }

        let eden = self.young.eden_active();
        verify_marking_region(eden, self.heap);

        let from = self.young.from_active();
        verify_marking_region(from, self.heap);

        let to = self.young.to_active();
        verify_marking_region(to, self.heap);
    }

    fn compute_forward(&mut self) {
        self.walk_old_and_young(|full, object, _address, object_size| {
            if object.header().is_marked_non_atomic() {
                let fwd = full.allocate(object_size);
                object.header_mut().set_fwdptr_non_atomic(fwd);
            }
        });

        self.old_protected.commit_single_region(self.old_top);
        self.old_committed = Region::new(self.old.total_start(), self.old_top);
    }

    fn update_references(&mut self) {
        self.walk_old_and_young(|full, object, _address, _| {
            if object.header().is_marked_non_atomic() {
                object.visit_reference_fields(|field| {
                    full.forward_reference(field);
                });
            }
        });

        for root in self.rootset {
            self.forward_reference(*root);
        }

        self.large_space.visit_objects(|object_start| {
            let object = object_start.to_mut_obj();

            if object.header().is_marked_non_atomic() {
                object.visit_reference_fields(|field| {
                    self.forward_reference(field);
                });
            }
        });
    }

    fn relocate(&mut self) {
        self.crossing_map.set_first_object(0.into(), 0);

        self.walk_old_and_young(|full, object, address, object_size| {
            if object.header().is_marked_non_atomic() {
                // get new location
                let dest = object.header().fwdptr_non_atomic();
                debug_assert!(full.old_committed.contains(dest));

                // determine location after relocated object
                let next_dest = dest.offset(object_size);
                debug_assert!(full.old_committed.valid_top(next_dest));

                if address != dest {
                    object.copy_to(dest, object_size);
                }

                // unmark object for next collection
                let dest_obj = dest.to_mut_obj();
                dest_obj.header_mut().unmark_non_atomic();

                full.old
                    .update_crossing(dest, next_dest, dest_obj.is_array_ref());
            }
        });
    }

    fn update_large_objects(&mut self) {
        self.large_space.remove_objects(|object_start| {
            let object = object_start.to_mut_obj();

            // reset cards for object, also do this for dead objects
            // to reset card entries to clean.
            if object.is_array_ref() {
                let object_end = object_start.offset(object.size());
                self.card_table.reset_region(object_start, object_end);
            } else {
                self.card_table.reset_addr(object_start);
            }

            if !object.header().is_marked_non_atomic() {
                // object is unmarked -> free it
                return false;
            }

            // unmark object for next collection
            object.header_mut().unmark_non_atomic();

            // keep object
            true
        });
    }

    fn reset_cards(&mut self) {
        let regions = self
            .old_protected
            .regions
            .iter()
            .map(|r| (r.start(), r.top()))
            .collect::<Vec<_>>();

        for ((start, top), init_top) in regions.into_iter().zip(&self.init_old_top) {
            let top = cmp::max(top, *init_top);
            self.card_table.reset_region(start, top);
        }
    }

    fn forward_reference(&mut self, slot: Slot) {
        let object_addr = slot.get();

        if self.heap.contains(object_addr) {
            debug_assert!(object_addr.to_obj().header().is_marked_non_atomic());

            if self.large_space.contains(object_addr) {
                // large objects do not move in memory
                return;
            }

            let fwd_addr = object_addr.to_obj().header().fwdptr_non_atomic();
            debug_assert!(self.heap.contains(fwd_addr));
            slot.set(fwd_addr);
        } else {
            debug_assert!(object_addr.is_null() || self.perm_space.contains(object_addr));
        }
    }

    fn walk_old_and_young<F>(&mut self, mut fct: F)
    where
        F: FnMut(&mut FullCollector, &mut Obj, Address, usize),
    {
        let old_regions = self
            .old_protected
            .regions
            .iter()
            .map(|r| r.active_region())
            .collect::<Vec<_>>();

        for old_region in old_regions {
            self.walk_region(old_region.start, old_region.end, &mut fct);
        }

        let used_region = self.young.eden_active();
        self.walk_region(used_region.start, used_region.end, &mut fct);

        let used_region = self.young.from_active();
        self.walk_region(used_region.start, used_region.end, &mut fct);

        // This is a bit strange at first: to-space might not be empty,
        // after too many survivors in the minor GC of the young gen.
        let used_region = self.young.to_active();
        self.walk_region(used_region.start, used_region.end, &mut fct);
    }

    fn walk_region<F>(&mut self, start: Address, end: Address, fct: &mut F)
    where
        F: FnMut(&mut FullCollector, &mut Obj, Address, usize),
    {
        let mut scan = start;

        while scan < end {
            let object = scan.to_mut_obj();

            if object.header().vtblptr().is_null() {
                scan = scan.add_ptr(1);
                continue;
            }

            let object_size = object.size();

            fct(self, object, scan, object_size);

            scan = scan.offset(object_size);
        }
    }

    fn allocate(&mut self, object_size: usize) -> Address {
        let addr = self.old_top;
        let next = self.old_top.offset(object_size);

        if next <= self.old_limit {
            self.old_top = next;
            return addr;
        }

        panic!("FAIL: Not enough space for objects in old generation.");
    }
}

fn verify_marking_region(region: Region, heap: Region) {
    walk_region(region, |obj, _address, _size| {
        if obj.header().is_marked_non_atomic() {
            obj.visit_reference_fields(|field| {
                let object_addr = field.get();

                if heap.contains(object_addr) {
                    assert!(object_addr.to_obj().header().is_marked_non_atomic());
                }
            });
        }
    });
}

fn walk_region<F>(region: Region, mut fct: F)
where
    F: FnMut(&mut Obj, Address, usize),
{
    let mut scan = region.start;

    while scan < region.end {
        let object = scan.to_mut_obj();

        if object.header().vtblptr().is_null() {
            scan = scan.add_ptr(1);
            continue;
        }

        let object_size = object.size();
        fct(object, scan, object_size);
        scan = scan.offset(object_size);
    }
}
<|endoftext|>


<commit_before>use crate::{api::prelude::*, proc_macros::*};

// Depreciated: use function layout()
// /// The `PopupAction` represent actions that can be sent to `PopupState`.
// pub enum PopupAction {
//     // placement of the popup relative to its target
//     UpdatePlacement,

//     // update the visiability status
//     UpdateVisibility,
// }

/// The `PopupState` handles the open and close behavior of the `Popup` widget.
#[derive(AsAny, Default)]
pub struct PopupState {
    //actions: Vec<PopupAction>,
}

impl PopupState {
    // Depreciated: use function layout()
    // /// If the placement property of the popup widget changes, its
    // /// bounds will be measured and the rendered widget will be placed
    // /// consuming the given position relative to its associated target.
    // pub fn update_placement(&mut self) {
    //	self.actions.push(PopupAction::UpdatePlacement);
    // }

    // Depreciated: use function layout()
    // /// the visibility property enables where do we place the popup
    // /// widget in relation to the given target.
    // pub fn update_visibility(&mut self) {
    //	self.actions.push(PopupAction::UpdateVisibility);
    // }

    // Deprecated: use function layout().
    // fn update_placement_internal(&mut self, _registry: &mut Registry, ctx: &mut Context) {
    //	if let Some(target) = ctx.widget().try_clone::<PopupTarget>("target") {
    //	    let current_bounds: Rectangle = ctx.widget().clone("bounds");
    //	    let current_constraint: Constraint = ctx.widget().clone("constraint");

    //	    let real_target_bounds = match target {
    //		PopupTarget::Entity(entity) => {
    //		    let target_position: Point = ctx.get_widget(entity).clone("position");

    //		    // WARNING: widget bounds (width an height values)
    //		    // will be measured as available space for the
    //		    // widget. Only in `post_layout_update` state it will
    //		    // reflect the effective size of the given entity.
    //		    let mut target_bounds: Rectangle = ctx.get_widget(entity).clone("bounds");
    //		    target_bounds.set_position(target_position);
    //		    target_bounds
    //		}
    //		PopupTarget::Point(mut point) => {
    //		    point.set_x(point.x() + current_bounds.width() / 2.0);
    //		    point.set_y(point.y() + current_bounds.height() / 2.0);
    //		    Rectangle::new(point, (0.0, 0.0))
    //		}
    //	    };

    //	    let placement: Placement = ctx.widget().clone_or_default("placement");

    //	    let new_popup_bounds = match placement {
    //		Placement::Left => {
    //		    let current_v_align: Alignment = ctx.widget().clone("v_align");

    //		    let x = real_target_bounds.x() - current_bounds.width();
    //		    let y = current_v_align.align_position(
    //			real_target_bounds.height(),
    //			current_bounds.height(),
    //			real_target_bounds.y(),
    //			real_target_bounds.y() + real_target_bounds.height(),
    //		    );

    //		    let width = current_bounds.width();
    //		    let height = current_v_align.align_measure(
    //			real_target_bounds.height(),
    //			current_bounds.height(),
    //			0.0,
    //			0.0,
    //		    );

    //		    Rectangle::new((x, y), current_constraint.perform((width, height)))
    //		}
    //		Placement::Right => {
    //		    let current_v_align: Alignment = ctx.widget().clone("v_align");

    //		    let x = real_target_bounds.x() + real_target_bounds.width();
    //		    let y = current_v_align.align_position(
    //			real_target_bounds.height(),
    //			current_bounds.height(),
    //			real_target_bounds.y(),
    //			real_target_bounds.y() + real_target_bounds.height(),
    //		    );

    //		    let width = current_bounds.width();
    //		    let height = current_v_align.align_measure(
    //			real_target_bounds.height(),
    //			current_bounds.height(),
    //			0.0,
    //			0.0,
    //		    );

    //		    Rectangle::new((x, y), current_constraint.perform((width, height)))
    //		}
    //		Placement::Top => {
    //		    let current_h_align: Alignment = ctx.widget().clone("h_align");

    //		    let x = current_h_align.align_position(
    //			real_target_bounds.width(),
    //			current_bounds.width(),
    //			real_target_bounds.x(),
    //			real_target_bounds.x() + real_target_bounds.width(),
    //		    );
    //		    let y = real_target_bounds.y() - current_bounds.height();
    //		    let width = current_h_align.align_measure(
    //			real_target_bounds.width(),
    //			current_bounds.width(),
    //			0.0,
    //			0.0,
    //		    );
    //		    let height = current_bounds.height();

    //		    Rectangle::new((x, y), current_constraint.perform((width, height)))
    //		}
    //		Placement::Bottom => {
    //		    let current_h_align: Alignment = ctx.widget().clone("h_align");

    //		    let x = current_h_align.align_position(
    //			real_target_bounds.width(),
    //			current_bounds.width(),
    //			real_target_bounds.x(),
    //			real_target_bounds.x() + real_target_bounds.width(),
    //		    );
    //		    let y = real_target_bounds.y() + real_target_bounds.height();
    //		    let width = current_h_align.align_measure(
    //			real_target_bounds.width(),
    //			current_bounds.width(),
    //			0.0,
    //			0.0,
    //		    );
    //		    let height = current_bounds.height();

    //		    Rectangle::new((x, y), current_constraint.perform((width, height)))
    //		}
    //	    };

    //	    ctx.widget().set::<Rectangle>("bounds", new_popup_bounds);
    // } else {
    //     println!("Target not found");
    // }
    //}

    // Deprecated: use function layout().
    // fn update_visibility_internal(&mut self, _registry: &mut Registry, ctx: &mut Context) {
    //	//if cfg!(feature = "log") {
    //	println!("popup2: update_visibility_internal: started");
    //	//}

    //	let mut widget = ctx.widget();
    //	let open = widget.clone::<bool>("open");
    //	let visibility: &mut Visibility = widget.get_mut("visibility");

    //	//if cfg!(feature = "log") {
    //	println!("popup2: Current status open: {:?}", open);
    //	println!("popup2: Current status Visibility: {:?}", visibility);
    //	//}

    //	match (open, *visibility) {
    //	    (true, Visibility::Visible) => {}
    //	    (true, Visibility::Hidden) => *visibility = Visibility::Visible,
    //	    (true, Visibility::Collapsed) => *visibility = Visibility::Visible,
    //	    (false, Visibility::Visible) => *visibility = Visibility::Collapsed,
    //	    (false, Visibility::Hidden) => *visibility = Visibility::Collapsed,
    //	    (false, Visibility::Collapsed) => {}
    //	}

    //	//if cfg!(feature = "log") {
    //	println!("popup2: Updated status open: {}", open);
    //	println!("popup2: Updated status visibility: {:?}", *visibility);
    //	println!("popup2: update_visibility_internal: finished");
    //	//}
    // }
}

impl State for PopupState {
    // fn update(&mut self, registry: &mut Registry, ctx: &mut Context) {
    //	let actions: Vec<PopupAction> = self.actions.drain(..).collect();
    //	for action in actions {
    //	    match action {
    //		PopupAction::UpdatePlacement => self.update_placement_internal(registry, ctx),
    //		PopupAction::UpdateVisibility => self.update_visibility_internal(registry, ctx),
    //	    }
    //	}
    // }
}

widget!(
    /// The `Popup` is used to presents content bound to target entity.
    ///
    /// The `target` is specified either via its widget id (`Entitiy`)
    /// or using a point coordinate (`Point`). The placmement of the
    /// popup widget itself is controlled via its `placement`
    /// property. An optional attribute (float), defines the
    /// margin between the target and the popup widget.
    ///
    /// [`placement`]: ../orbtk_core/render_object/enum.Placement.html
    ///
    /// **style:** `popup``
    Popup<PopupState> : KeyDownHandler, MouseHandler {
    /// Sets or shares the background property.
    background: Brush,

    /// Sets or shares the border brush property.
    border_brush: Brush,

    /// Sets or shares the border radius property.
    border_radius: f64,

    /// Sets or shares the border thickness property.
    border_width: Thickness,

    /// Sets or shares the popup open state.
    open: bool,

    /// Sets or shares the padding property.
    padding: Thickness,

    /// Sets or shares the placement property relative to the
    /// target position. Valid placement variants are defined via
    /// the `Placement` enumeration.
    placement: Placement,

    /// Sets or shares the offset property that assignes a margin
    /// between popup and target entity.
    offset: f64,

    ///
    /// Defined ether as an entity (Entity), or as a point
    /// coordinate (Point).
    target: PopupTarget
    }
);

impl Template for Popup {
    fn template(self, _id: Entity, _: &mut BuildContext) -> Self {
        self.name("Popup").style("popup").open(false)
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
        Box::new(PopupRenderObject::new())
    }

    fn layout(&self) -> Box<dyn Layout> {
        PopupLayout::new().into()
    }
}
<commit_msg>orbtk_widget: popup update<commit_after>use crate::{api::prelude::*, proc_macros::*};

/// The `PopupState` handles the open and close behavior of the `Popup` widget.
#[derive(AsAny, Default)]
pub struct PopupState {
    //actions: Vec<PopupAction>,
}

impl PopupState {}

impl State for PopupState {}

widget!(
    /// The `Popup` is used to presents content bound to target entity.
    ///
    /// The `target` is specified either via its widget id (`Entitiy`)
    /// or using a point coordinate (`Point`). The placmement of the
    /// popup widget itself is controlled via its `placement`
    /// property. An optional attribute (float), defines the
    /// margin between the target and the popup widget.
    ///
    /// [`placement`]: ../orbtk_core/render_object/enum.Placement.html
    ///
    /// **style:** `popup``
    Popup<PopupState> : KeyDownHandler, MouseHandler {
    /// Sets or shares the background property.
    background: Brush,

    /// Sets or shares the border brush property.
    border_brush: Brush,

    /// Sets or shares the border radius property.
    border_radius: f64,

    /// Sets or shares the border thickness property.
    border_width: Thickness,

    /// Sets or shares the popup open state.
    open: bool,

    /// Sets or shares the padding property.
    padding: Thickness,

    /// Sets or shares the placement property relative to the
    /// target position. Valid placement variants are defined via
    /// the `Placement` enumeration.
    placement: Placement,

    /// Sets or shares the offset property that assignes a margin
    /// between popup and target entity.
    offset: f64,

    ///
    /// Defined ether as an entity (Entity), or as a point
    /// coordinate (Point).
    target: PopupTarget
    }
);

impl Template for Popup {
    fn template(self, _id: Entity, _: &mut BuildContext) -> Self {
        self.name("Popup").style("popup").open(false)
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
        Box::new(PopupRenderObject::new())
    }

    fn layout(&self) -> Box<dyn Layout> {
        PopupLayout::new().into()
    }
}
<|endoftext|>


<commit_before>//! Wayland scanner crate
//!
//!
//! This crate is a rust equivalent of the wayland-scanner tool from the
//! official wayland C library.
//!
//! You can use in your build script to generate the rust code for any
//! wayland protocol file, to use alongside the `wayland_client` and
//! `wayland_server` crate to build your applications.
//!
//! ## How to use this crate
//!
//! This crate is to be used in a build script. It provides you two
//! functions, `generate_code` and `generate_interfaces`. They'll
//! allow you to generate the code to use with the `wayland_client` or
//! `wayland_server` crates for any XML wayland protocol file (NB: you don't
//! need to do it for the core protocol, which is already included in both crates).
//!
//! First, have the XML files you want to use in your project, somewhere the build script
//! will be able to read them.
//!
//! Then, you'll need to invoke both `generate_interfaces` *and* `generate_code` for
//! each of these files.
//!
//! A sample build script:
//!
//! ```no_run
//! extern crate wayland_scanner;
//!
//! use std::env::var;
//! use std::path::Path;
//!
//! use wayland_scanner::{Side, generate_code, generate_interfaces};
//!
//! fn main() {
//!     // Location of the xml file, relative to the `Cargo.toml`
//!     let protocol_file = "./my_protocol.xml";
//!
//!     // Target directory for the generate files
//!     let out_dir_str = var("OUT_DIR").unwrap();
//!     let out_dir = Path::new(&out_dir_str);
//!
//!     generate_code(
//!         protocol_file,
//!         out_dir.join("my_protocol_api.rs"),
//!         Side::Client, // Replace by `Side::Server` for server-side code
//!     );
//!
//!     // interfaces are the same for client and server
//!     generate_interfaces(
//!         protocol_file,
//!         out_dir.join("my_protocol_interfaces.rs")
//!     );
//! }
//! ```
//!
//! The above example will output two `.rs` files in the `OUT_DIR` defined by
//! cargo. Then, you'll need to include these two generated files (using the
//! macro of the same name) to make this code available in your crate.
//!
//! ```ignore
//! // The generated code will import stuff from wayland_sys
//! extern crate wayland_sys;
//! extern crate wayland_client;
//!
//! // Re-export only the actual code, and then only use this re-export
//! // The `generated` module below is just some boilerplate to properly isolate stuff
//! // and avoid exposing internal details.
//! //
//! // You can use all the types from my_procol as if they went from `wayland_client::protocol`.
//! pub use generated::client as my_protocol;
//!
//! mod generated {
//!     // The generated code tends to trigger a lot of warnings
//!     // so we isole it into a very permissive module
//!     #![allow(dead_code,non_camel_case_types,unused_unsafe,unused_variables)]
//!     #![allow(non_upper_case_globals,non_snake_case,unused_imports)]
//!
//!     pub mod interfaces {
//!         // include the interfaces, they just need to be accessible to the generated code
//!         // so this module is `pub` so that it can be imported by the other one.
//!         include!(concat!(env!("OUT_DIR"), "/my_protocol_interfaces.rs"));
//!     }
//!
//!     pub mod client {
//!         // These import are mandatory, and need to by `pub`, because
//!         // submodules in the generated code will try to import them.
//!         // Hopefully someday pub(restricted) and friends will
//!         // allow for a cleaner way to do that
//!         #[doc(hidden)] pub use wayland_client::{Proxy, Handler, EventQueueHandle};
//!         // Replace the above line with this for server-side:
//!         // #[doc(hidden)] pub use wayland_server::{Resource, Handler, EventLoopHandle};
//!         #[doc(hidden)] pub use super::interfaces;
//!         // If you protocol interacts with objects from other protocols, you'll need to import
//!         // their modules, like so:
//!         #[doc(hidden)] pub use wayland_client::protocol::{wl_surface, wl_region};
//!         include!(concat!(env!("OUT_DIR"), "/my_protocol_code.rs"));
//!     }
//! }
//! ```
extern crate xml;

use std::fs::{File, OpenOptions};
use std::path::Path;

mod util;
mod parse;
mod protocol;
mod side;
mod interface_gen;
mod code_gen;

pub use side::Side;

fn load_xml<P: AsRef<Path>>(prot: P) -> protocol::Protocol {
    let pfile = File::open(prot).unwrap();
    parse::parse_stream(pfile)
}

/// Generate the interfaces for a protocol
///
/// See this crate toplevel documentation for details.
///
/// Args:
///
/// - `protocol`: a path to the XML file describing the protocol, absolute or relative to
///   the build script using this function.
/// - `target`: the path of the file to store this interfaces in.
pub fn generate_interfaces<P1: AsRef<Path>, P2: AsRef<Path>>(protocol: P1, target: P2) {
    let protocol = load_xml(protocol);
    let mut out = OpenOptions::new().write(true).truncate(true).create(true).open(target).unwrap();
    interface_gen::generate_interfaces(protocol, &mut out);
}

/// Generate the code for a protocol
///
/// See this crate toplevel documentation for details.
///
/// Args:
///
/// - `protocol`: a path to the XML file describing the protocol, absolute or relative to
///   the build script using this function.
/// - `target`: the path of the file to store the code in.
/// - `side`: the side (client or server) to generate code for.
pub fn generate_code<P1: AsRef<Path>, P2: AsRef<Path>>(prot: P1, target: P2, side: Side) {
    let protocol = load_xml(prot);
    let mut out = OpenOptions::new().write(true).truncate(true).create(true).open(target).unwrap();
    code_gen::write_protocol(protocol, &mut out, side).unwrap()
}
<commit_msg>scanner: update doc with *Result imports<commit_after>//! Wayland scanner crate
//!
//!
//! This crate is a rust equivalent of the wayland-scanner tool from the
//! official wayland C library.
//!
//! You can use in your build script to generate the rust code for any
//! wayland protocol file, to use alongside the `wayland_client` and
//! `wayland_server` crate to build your applications.
//!
//! ## How to use this crate
//!
//! This crate is to be used in a build script. It provides you two
//! functions, `generate_code` and `generate_interfaces`. They'll
//! allow you to generate the code to use with the `wayland_client` or
//! `wayland_server` crates for any XML wayland protocol file (NB: you don't
//! need to do it for the core protocol, which is already included in both crates).
//!
//! First, have the XML files you want to use in your project, somewhere the build script
//! will be able to read them.
//!
//! Then, you'll need to invoke both `generate_interfaces` *and* `generate_code` for
//! each of these files.
//!
//! A sample build script:
//!
//! ```no_run
//! extern crate wayland_scanner;
//!
//! use std::env::var;
//! use std::path::Path;
//!
//! use wayland_scanner::{Side, generate_code, generate_interfaces};
//!
//! fn main() {
//!     // Location of the xml file, relative to the `Cargo.toml`
//!     let protocol_file = "./my_protocol.xml";
//!
//!     // Target directory for the generate files
//!     let out_dir_str = var("OUT_DIR").unwrap();
//!     let out_dir = Path::new(&out_dir_str);
//!
//!     generate_code(
//!         protocol_file,
//!         out_dir.join("my_protocol_api.rs"),
//!         Side::Client, // Replace by `Side::Server` for server-side code
//!     );
//!
//!     // interfaces are the same for client and server
//!     generate_interfaces(
//!         protocol_file,
//!         out_dir.join("my_protocol_interfaces.rs")
//!     );
//! }
//! ```
//!
//! The above example will output two `.rs` files in the `OUT_DIR` defined by
//! cargo. Then, you'll need to include these two generated files (using the
//! macro of the same name) to make this code available in your crate.
//!
//! ```ignore
//! // The generated code will import stuff from wayland_sys
//! extern crate wayland_sys;
//! extern crate wayland_client;
//!
//! // Re-export only the actual code, and then only use this re-export
//! // The `generated` module below is just some boilerplate to properly isolate stuff
//! // and avoid exposing internal details.
//! //
//! // You can use all the types from my_procol as if they went from `wayland_client::protocol`.
//! pub use generated::client as my_protocol;
//!
//! mod generated {
//!     // The generated code tends to trigger a lot of warnings
//!     // so we isole it into a very permissive module
//!     #![allow(dead_code,non_camel_case_types,unused_unsafe,unused_variables)]
//!     #![allow(non_upper_case_globals,non_snake_case,unused_imports)]
//!
//!     pub mod interfaces {
//!         // include the interfaces, they just need to be accessible to the generated code
//!         // so this module is `pub` so that it can be imported by the other one.
//!         include!(concat!(env!("OUT_DIR"), "/my_protocol_interfaces.rs"));
//!     }
//!
//!     pub mod client {
//!         // These import are mandatory, and need to by `pub`, because
//!         // submodules in the generated code will try to import them.
//!         // Hopefully someday pub(restricted) and friends will
//!         // allow for a cleaner way to do that
//!         #[doc(hidden)] pub use wayland_client::{Proxy, Handler, EventQueueHandle, RequestResult};
//!         // Replace the above line with this for server-side:
//!         // #[doc(hidden)] pub use wayland_server::{Resource, Handler, EventLoopHandle, EventResult};
//!         #[doc(hidden)] pub use super::interfaces;
//!         // If you protocol interacts with objects from other protocols, you'll need to import
//!         // their modules, like so:
//!         #[doc(hidden)] pub use wayland_client::protocol::{wl_surface, wl_region};
//!         include!(concat!(env!("OUT_DIR"), "/my_protocol_code.rs"));
//!     }
//! }
//! ```
extern crate xml;

use std::fs::{File, OpenOptions};
use std::path::Path;

mod util;
mod parse;
mod protocol;
mod side;
mod interface_gen;
mod code_gen;

pub use side::Side;

fn load_xml<P: AsRef<Path>>(prot: P) -> protocol::Protocol {
    let pfile = File::open(prot).unwrap();
    parse::parse_stream(pfile)
}

/// Generate the interfaces for a protocol
///
/// See this crate toplevel documentation for details.
///
/// Args:
///
/// - `protocol`: a path to the XML file describing the protocol, absolute or relative to
///   the build script using this function.
/// - `target`: the path of the file to store this interfaces in.
pub fn generate_interfaces<P1: AsRef<Path>, P2: AsRef<Path>>(protocol: P1, target: P2) {
    let protocol = load_xml(protocol);
    let mut out = OpenOptions::new().write(true).truncate(true).create(true).open(target).unwrap();
    interface_gen::generate_interfaces(protocol, &mut out);
}

/// Generate the code for a protocol
///
/// See this crate toplevel documentation for details.
///
/// Args:
///
/// - `protocol`: a path to the XML file describing the protocol, absolute or relative to
///   the build script using this function.
/// - `target`: the path of the file to store the code in.
/// - `side`: the side (client or server) to generate code for.
pub fn generate_code<P1: AsRef<Path>, P2: AsRef<Path>>(prot: P1, target: P2, side: Side) {
    let protocol = load_xml(prot);
    let mut out = OpenOptions::new().write(true).truncate(true).create(true).open(target).unwrap();
    code_gen::write_protocol(protocol, &mut out, side).unwrap()
}
<|endoftext|>