<commit_before>//! DPLL Algorithm implementation with unit-clause propagation and
//! pure literal assignment.

use satyrs::cnf::{CNF, Assignment, PartialAssignment};
use satyrs::heuristics::jw;

#[allow(non_snake_case)]
pub fn DPLL(cnf: &CNF, verbose: bool) -> Option<(Assignment, PartialAssignment)> {
    let mut p_assn = PartialAssignment::new(cnf.nvar as usize);
    match _dpll(cnf, &mut p_assn, verbose) {
        Some(assn) => {
            Some((assn.assignment
                      .iter()
                      .map(|a| {
                          match *a {
                              Some(a) => a,
                              None => true,
                          }
                      })
                      .collect(),
                  assn))
        }
        None => None,
    }
}

fn _dpll(cnf: &CNF, p_assn: &mut PartialAssignment, verbose: bool) -> Option<PartialAssignment> {
    if verbose {
        println!("====DPLL====\n");
        println!("{}\n{}", cnf, p_assn);
    }
    // If consistent set of literals, return True
    if cnf.clauses.is_empty() {
        let _p_assn = p_assn.clone();
        return Some(_p_assn);  // Display optional value
    }

    // If contains an empty clause return None
    for clause in cnf.clauses.values() {
        if clause.is_empty() {
            return None;
        }
    }

    // For every unit-clause, unit-propagate
    let mut _cnf = cnf.clone();
    let mut units = _cnf.units.clone();
    while !units.is_empty() {
        if verbose {
            println!("Simplifying unit clause(s): {:?}", units)
        }
        for unit in units.iter() {
            // Previous versions of this for loop could have unit-propagated and
            // remove the unit clause here, so it's not necessary that the unit clause id
            // still exists in the clauses.
            if let Some(clause) = _cnf.clauses.get(&unit) {
                // Then via unit propagation we've created an empty clause; no solution down this
                // path
                if clause.is_empty() {
                    return None;
                }
                let lit: i32 = zeroth!(clause);
                p_assn.assign_literal(lit);
                // TODO: Could have check for empty clauses in unit_propagate
            }
            _cnf.unit_propagate(*unit); // Only propagate in the clone
        }
        units = _cnf.units.clone();
    }
    // Pure literal elimination
    // We can iterate through old cnf occurrences and propagate on new _cnf
    for lit in cnf.occurrences.keys() {
        let neg = *lit ^ 1;
        if !cnf.occurrences.contains_key(&neg) {
            p_assn.assign_literal(*lit);
            _cnf.propagate(*lit);
        }
    }

    // Clone for the right literal, since we're going to propagate _cnf with the left literal
    let mut r_cnf = _cnf.clone();

    // Choose literal L for split
    // Heuristics don't do random checks for empty occurrences.
    // If there are no occurrences,
    if _cnf.occurrences.is_empty() {
        // FIXME: horrible hack
        // Bookkeeping is not implemented perfectly, we can get to this state and (just from
        // empirics) clauses will either be EMPTY or will have any number of empty clauses.
        // Intutition: if clauses is EMPTY, then there are no occurrences but also no clauses, so
        // we're good to go. If clauses is NOT empty, then there are no occurrences but there are
        // clauses, so the clauses are empty, so we return none.
        if _cnf.clauses.is_empty() {
            // Good
            let _p_assn = p_assn.clone();
            return Some(_p_assn);
        } else {
            // Bad
            return None;
        }
    }
    let lit = jw(&_cnf);

    if verbose {
        if lit & 1 == 0 {
            // True
            println!("Splitting on {}", lit / 2);
        } else {
            // False
            println!("Splitting on -{}", lit / 2);
        }
    }
    // Propagate literal
    _cnf.propagate(lit);

    // Return DPLL with L and -L
    p_assn.assign_literal(lit);

    if verbose {
        println!("Trying left");
    }
    let left = _dpll(&_cnf, p_assn, verbose);
    // If this branch works, return left.
    if left.is_some() {
        return left;
    }

    // Otherwise, unassign this literal, assign its negation, and try the subsequent formula.
    let neg = lit ^ 1;
    p_assn.unassign_literal(lit);
    p_assn.assign_literal(neg);

    r_cnf.propagate(neg);
    if verbose {
        println!("Trying right");
    }
    _dpll(&r_cnf, p_assn, verbose)
}
<commit_msg>Add another possible bug source<commit_after>//! DPLL Algorithm implementation with unit-clause propagation and
//! pure literal assignment.

use satyrs::cnf::{CNF, Assignment, PartialAssignment};
use satyrs::heuristics::jw;

#[allow(non_snake_case)]
pub fn DPLL(cnf: &CNF, verbose: bool) -> Option<(Assignment, PartialAssignment)> {
    let mut p_assn = PartialAssignment::new(cnf.nvar as usize);
    match _dpll(cnf, &mut p_assn, verbose) {
        Some(assn) => {
            Some((assn.assignment
                      .iter()
                      .map(|a| {
                          match *a {
                              Some(a) => a,
                              None => true,
                          }
                      })
                      .collect(),
                  assn))
        }
        None => None,
    }
}

fn _dpll(cnf: &CNF, p_assn: &mut PartialAssignment, verbose: bool) -> Option<PartialAssignment> {
    if verbose {
        println!("====DPLL====\n");
        println!("{}\n{}", cnf, p_assn);
    }
    // If consistent set of literals, return True
    if cnf.clauses.is_empty() {
        let _p_assn = p_assn.clone();
        return Some(_p_assn);  // Display optional value
    }

    // If contains an empty clause return None
    for clause in cnf.clauses.values() {
        if clause.is_empty() {
            return None;
        }
    }

    // For every unit-clause, unit-propagate
    let mut _cnf = cnf.clone();
    let mut units = _cnf.units.clone();
    while !units.is_empty() {
        if verbose {
            println!("Simplifying unit clause(s): {:?}", units)
        }
        for unit in units.iter() {
            // Previous versions of this for loop could have unit-propagated and
            // remove the unit clause here, so it's not necessary that the unit clause id
            // still exists in the clauses.
            if let Some(clause) = _cnf.clauses.get(&unit) {
                // Then via unit propagation we've created an empty clause; no solution down this
                // path
                if clause.is_empty() {
                    return None;
                }
                let lit: i32 = zeroth!(clause);
                p_assn.assign_literal(lit);
                // TODO: Could have check for empty clauses in unit_propagate
            }
            _cnf.unit_propagate(*unit); // Only propagate in the clone
        }
        units = _cnf.units.clone();
    }
    // Pure literal elimination
    // We can iterate through old cnf occurrences and propagate on new _cnf
    // FIXME XXX: bug here between checking _cnf vs cnf?
    for lit in cnf.occurrences.keys() {
        let neg = *lit ^ 1;
        if !cnf.occurrences.contains_key(&neg) {
            p_assn.assign_literal(*lit);
            _cnf.propagate(*lit);
        }
    }

    // Clone for the right literal, since we're going to propagate _cnf with the left literal
    let mut r_cnf = _cnf.clone();

    // Choose literal L for split
    // Heuristics don't do random checks for empty occurrences.
    // If there are no occurrences,
    if _cnf.occurrences.is_empty() {
        // FIXME: horrible hack
        // Bookkeeping is not implemented perfectly, we can get to this state and (just from
        // empirics) clauses will either be EMPTY or will have any number of empty clauses.
        // Intutition: if clauses is EMPTY, then there are no occurrences but also no clauses, so
        // we're good to go. If clauses is NOT empty, then there are no occurrences but there are
        // clauses, so the clauses are empty, so we return none.
        if _cnf.clauses.is_empty() {
            // Good
            let _p_assn = p_assn.clone();
            return Some(_p_assn);
        } else {
            // Bad
            return None;
        }
    }
    let lit = jw(&_cnf);

    if verbose {
        if lit & 1 == 0 {
            // True
            println!("Splitting on {}", lit / 2);
        } else {
            // False
            println!("Splitting on -{}", lit / 2);
        }
    }
    // Propagate literal
    _cnf.propagate(lit);

    // Return DPLL with L and -L
    p_assn.assign_literal(lit);

    if verbose {
        println!("Trying left");
    }
    let left = _dpll(&_cnf, p_assn, verbose);
    // If this branch works, return left.
    if left.is_some() {
        return left;
    }

    // Otherwise, unassign this literal, assign its negation, and try the subsequent formula.
    let neg = lit ^ 1;
    p_assn.unassign_literal(lit);
    p_assn.assign_literal(neg);

    r_cnf.propagate(neg);
    if verbose {
        println!("Trying right");
    }
    _dpll(&r_cnf, p_assn, verbose)
}
<|endoftext|>


<commit_before>pub use self::{
	browse::*,
	connection::*,
	enumerate_domains::*,
	query_record::*,
	records::Record,
	register::*,
	resolve::*,
};

mod browse;
mod connection;
mod enumerate_domains;
mod query_record;
mod records;
mod register;
mod resolve;

use dns_consts::{
	Class,
	Type,
};

/// Purge record from cache
///
/// See [`DNSServiceReconfirmRecord`](https://developer.apple.com/documentation/dnssd/1804726-dnsservicereconfirmrecord).
pub fn reconfirm_record(
	interface: ::interface::Interface,
	fullname: &str,
	rr_type: Type,
	rr_class: Class,
	rdata: &[u8],
) -> ::std::io::Result<()> {
	::init();

	let fullname = ::cstr::CStr::from(&fullname)?;
	::raw::reconfirm_record(
		0, // no flags
		interface.into_raw(),
		&fullname,
		rr_type,
		rr_class,
		rdata,
	);

	Ok(())
}

/// Full name consiting of (up to) three parts
pub struct FullName<'a> {
	/// (unescaped) service name (becomes single label in full name)
	pub service: Option<&'a str>,
	/// registration type (valid names don't need escaping)
	pub reg_type: &'a str,
	/// (escaped) domain name (most names don't need escaping)
	pub domain: &'a str,
}

impl<'a> FullName<'a> {
	/// Escape and concatenate all three parts to a full name
	///
	/// See [`DNSServiceConstructFullName`](https://developer.apple.com/documentation/dnssd/1804753-dnsserviceconstructfullname)
	pub fn construct(&self) -> ::std::io::Result<String> {
		use std::io;

		let service = ::cstr::NullableCStr::from(&self.service)?;
		let reg_type = ::cstr::CStr::from(&self.reg_type)?;
		let domain = ::cstr::CStr::from(&self.domain)?;

		const SIZE: usize = ::ffi::MAX_DOMAIN_NAME + 200;
		let mut buf: Vec<u8> = Vec::new();
		buf.reserve(SIZE);
		let len = unsafe {
			::ffi::DNSServiceConstructFullName(
				buf.as_mut_ptr() as *mut i8,
				service.as_ptr(),
				reg_type.as_ptr(),
				domain.as_ptr(),
			)
		};

		if len < 0 {
			return Err(io::Error::new(
				io::ErrorKind::InvalidInput,
				"invalid input",
			));
		}

		unsafe {
			buf.set_len(len as usize);
		}

		String::from_utf8(buf)
			.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))
	}
}
<commit_msg>use c_char for casting buffer pointer (fixes #15)<commit_after>pub use self::{
	browse::*,
	connection::*,
	enumerate_domains::*,
	query_record::*,
	records::Record,
	register::*,
	resolve::*,
};

mod browse;
mod connection;
mod enumerate_domains;
mod query_record;
mod records;
mod register;
mod resolve;

use dns_consts::{
	Class,
	Type,
};
use std::os::raw::c_char;

/// Purge record from cache
///
/// See [`DNSServiceReconfirmRecord`](https://developer.apple.com/documentation/dnssd/1804726-dnsservicereconfirmrecord).
pub fn reconfirm_record(
	interface: ::interface::Interface,
	fullname: &str,
	rr_type: Type,
	rr_class: Class,
	rdata: &[u8],
) -> ::std::io::Result<()> {
	::init();

	let fullname = ::cstr::CStr::from(&fullname)?;
	::raw::reconfirm_record(
		0, // no flags
		interface.into_raw(),
		&fullname,
		rr_type,
		rr_class,
		rdata,
	);

	Ok(())
}

/// Full name consiting of (up to) three parts
pub struct FullName<'a> {
	/// (unescaped) service name (becomes single label in full name)
	pub service: Option<&'a str>,
	/// registration type (valid names don't need escaping)
	pub reg_type: &'a str,
	/// (escaped) domain name (most names don't need escaping)
	pub domain: &'a str,
}

impl<'a> FullName<'a> {
	/// Escape and concatenate all three parts to a full name
	///
	/// See [`DNSServiceConstructFullName`](https://developer.apple.com/documentation/dnssd/1804753-dnsserviceconstructfullname)
	pub fn construct(&self) -> ::std::io::Result<String> {
		use std::io;

		let service = ::cstr::NullableCStr::from(&self.service)?;
		let reg_type = ::cstr::CStr::from(&self.reg_type)?;
		let domain = ::cstr::CStr::from(&self.domain)?;

		const SIZE: usize = ::ffi::MAX_DOMAIN_NAME + 200;
		let mut buf: Vec<u8> = Vec::new();
		buf.reserve(SIZE);
		let len = unsafe {
			::ffi::DNSServiceConstructFullName(
				buf.as_mut_ptr() as *mut c_char,
				service.as_ptr(),
				reg_type.as_ptr(),
				domain.as_ptr(),
			)
		};

		if len < 0 {
			return Err(io::Error::new(
				io::ErrorKind::InvalidInput,
				"invalid input",
			));
		}

		unsafe {
			buf.set_len(len as usize);
		}

		String::from_utf8(buf)
			.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))
	}
}
<|endoftext|>


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

//! Utilities for working with sessions.
//!
//! Sessions are created per action request and should be used as the only way
//! to communicate with the server. Sessions are responsible for handling action
//! errors (when something goes wrong) or notifying the server that the action
//! finished (by sending appropriate status signal).
//!
//! They also keep track of various statistics (such as number of transferred
//! bytes, action runtime, etc.) and stop the execution if they exceed limits
//! for a particular request.

mod demand;
mod error;
mod response;
mod sink;

use std::convert::TryInto;

use log::{error, info};

use crate::action;
use crate::message;
pub use self::demand::{Demand, Header, Payload};
pub use self::error::{Error, ParseError};
use self::response::{Response, Status};
pub use self::sink::{Sink};

/// A specialized `Result` type for sessions.
pub type Result<T> = std::result::Result<T, Error>;

/// Object associating a session with particular action request.
///
/// This is just a convenience type used to avoid threading large numbers of
/// parameters through different function calls.
///
/// Note that the payload can be quite large object, so it should not be stored
/// with the session itself. The payload should be consumed as soon as the
/// request is dispatched to a particular handler and parsed to a concrete type.
pub struct Task<'s, S: Session> {
    /// A session that this task should be run on.
    pub session: &'s mut S,
    /// Serialized data of the action request.
    pub payload: Payload,
}

impl<'s, S: Session> Task<'s, S> {

    /// Executes the task with a particular action handler.
    pub fn execute<R, H>(self, handler: H) -> Result<()>
    where
        R: action::Request,
        H: FnOnce(&mut S, R) -> Result<()>,
    {
        let request = self.payload.parse()?;
        handler(self.session, request)
    }
}

/// Processes given message, handling all errors.
///
/// This function takes a message from the GRR server and interprets it as an
/// action request. It creates a new session object and dispatches the request
/// to an appropriate action handler. Once the action finishes, the function
/// will send a final status message, informing the server about a success
/// or a failure.
///
/// Note that if action execution fails, this function deals with all the errors
/// by sending appropriate information to the server (if possible), logging them
/// and failing hard if a critical error (e.g. communication failure) occurred.
pub fn handle<M>(message: M)
where
    M: TryInto<Demand, Error=ParseError>,
{
    let demand = match message.try_into() {
        Ok(demand) => {
            info!("requested to execute the '{}' action", demand.action);
            demand
        }
        Err(error) => {
            error!("failed to parse the message: {}", error);
            return;
        }
    };

    let mut session = Action::from_demand(&demand);

    let result = action::dispatch(&demand.action, Task {
        session: &mut session,
        payload: demand.payload,
    });

    if let Err(ref error) = result {
        error!("failed to execute the '{}' action: {}", demand.action, error);
    } else {
        info!("finished executing the '{}' action", demand.action);
    }

    let message = match session.status(result).try_into() {
        Ok(message) => message,
        Err(error) => {
            // If we cannot encode the final status message, there is nothing
            // we can do to notify the server, as status is responsible for
            // reporting errors. We can only log the error and carry on.
            error!("failed to encode status message: {}", error);
            return;
        }
    };

    message::send(message);
}

/// Abstraction for various kinds of sessions.
pub trait Session {
    /// Sends a reply to the flow that call the action.
    fn reply<R>(&mut self, response: R) -> Result<()>
    where R: action::Response;

    /// Sends a message to a particular sink.
    fn send<R>(&mut self, sink: Sink, response: R) -> Result<()>
    where R: action::Response;
}

/// A session type for unrequested action executions.
///
/// Certain kind of actions are executed not only when a server flow decides to
/// do so, but also upon particular kind of events (e.g. the agent's startup).
/// In such cases, when one needs to trigger action execution manually, ad-hoc
/// sessions should be used.
pub struct Adhoc;

impl Session for Adhoc {

    // TODO: Session trait should be probably split into two traits and then
    // make the actions that do not care about the `reply` method implement the
    // simpler one.
    fn reply<R>(&mut self, response: R) -> Result<()>
    where
        R: action::Response,
    {
        error!("attempted to reply to an ad-hoc session, dropping response");
        drop(response);

        Ok(())
    }

    fn send<R>(&mut self, sink: Sink, response: R) -> Result<()>
    where
        R: action::Response,
    {
        send(sink.wrap(response))?;

        Ok(())
    }
}

/// A session type for ordinary action requests.
///
/// This is a normal session type that that is associated with some flow on the
/// server. It keeps track of the responses it sends and collects statistics
/// about network and runtime utilization to kill the action if it is needed.
pub struct Action {
    header: Header,
    next_response_id: u64,
}

impl Action {

    /// Constructs a new session for the given `demand` object.
    pub fn from_demand(demand: &Demand) -> Action {
        // Response identifiers that GRR agents use start at 1. Unfortunately,
        // the server uses this assumption (to determine the number of expected
        // responses when status message is received), so we have to follow this
        // behaviour in RRG as well.
        Action {
            header: demand.header.clone(),
            next_response_id: 1,
        }
    }

    /// Wraps an action response to a session-specific response.
    fn wrap<R>(&self, response: R) -> Response<R>
    where
        R: action::Response
    {
        Response {
            session_id: self.header.session_id.clone(),
            request_id: Some(self.header.request_id),
            response_id: Some(self.next_response_id),
            data: response,
        }
    }

    /// Wraps an action result to a session-specific status response.
    ///
    /// Note that this method consumes the session. The reason for this is that
    /// status response should be obtained as the very last response and no
    /// further replies should be possible after that.
    fn status(self, result: Result<()>) -> Status {
        Status {
            session_id: self.header.session_id,
            request_id: self.header.request_id,
            response_id: self.next_response_id,
            result: result,
        }
    }
}

impl Session for Action {

    fn reply<R: action::Response>(&mut self, response: R) -> Result<()> {
        send(self.wrap(response))?;
        self.next_response_id += 1;

        Ok(())
    }

    fn send<R>(&mut self, sink: Sink, response: R) -> Result<()>
    where
        R: action::Response,
    {
        send(sink.wrap(response))?;

        Ok(())
    }
}

/// Sends a session response to the server.
///
/// Note that this function is not exposed on purpose. Actions should send
/// responses through session objects which introduce a layer of safety. `send`
/// is a low-level utility supposed to be used internally.
fn send<R>(response: Response<R>) -> Result<()>
where
    R: action::Response,
{
    let message = response.try_into()?;
    message::send(message);

    Ok(())
}
<commit_msg>Add (stub) support for heartbeat in sessions.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Utilities for working with sessions.
//!
//! Sessions are created per action request and should be used as the only way
//! to communicate with the server. Sessions are responsible for handling action
//! errors (when something goes wrong) or notifying the server that the action
//! finished (by sending appropriate status signal).
//!
//! They also keep track of various statistics (such as number of transferred
//! bytes, action runtime, etc.) and stop the execution if they exceed limits
//! for a particular request.

mod demand;
mod error;
mod response;
mod sink;

use std::convert::TryInto;

use log::{error, info};

use crate::action;
use crate::message;
pub use self::demand::{Demand, Header, Payload};
pub use self::error::{Error, ParseError};
use self::response::{Response, Status};
pub use self::sink::{Sink};

/// A specialized `Result` type for sessions.
pub type Result<T> = std::result::Result<T, Error>;

/// Object associating a session with particular action request.
///
/// This is just a convenience type used to avoid threading large numbers of
/// parameters through different function calls.
///
/// Note that the payload can be quite large object, so it should not be stored
/// with the session itself. The payload should be consumed as soon as the
/// request is dispatched to a particular handler and parsed to a concrete type.
pub struct Task<'s, S: Session> {
    /// A session that this task should be run on.
    pub session: &'s mut S,
    /// Serialized data of the action request.
    pub payload: Payload,
}

impl<'s, S: Session> Task<'s, S> {

    /// Executes the task with a particular action handler.
    pub fn execute<R, H>(self, handler: H) -> Result<()>
    where
        R: action::Request,
        H: FnOnce(&mut S, R) -> Result<()>,
    {
        let request = self.payload.parse()?;
        handler(self.session, request)
    }
}

/// Processes given message, handling all errors.
///
/// This function takes a message from the GRR server and interprets it as an
/// action request. It creates a new session object and dispatches the request
/// to an appropriate action handler. Once the action finishes, the function
/// will send a final status message, informing the server about a success
/// or a failure.
///
/// Note that if action execution fails, this function deals with all the errors
/// by sending appropriate information to the server (if possible), logging them
/// and failing hard if a critical error (e.g. communication failure) occurred.
pub fn handle<M>(message: M)
where
    M: TryInto<Demand, Error=ParseError>,
{
    let demand = match message.try_into() {
        Ok(demand) => {
            info!("requested to execute the '{}' action", demand.action);
            demand
        }
        Err(error) => {
            error!("failed to parse the message: {}", error);
            return;
        }
    };

    let mut session = Action::from_demand(&demand);

    let result = action::dispatch(&demand.action, Task {
        session: &mut session,
        payload: demand.payload,
    });

    if let Err(ref error) = result {
        error!("failed to execute the '{}' action: {}", demand.action, error);
    } else {
        info!("finished executing the '{}' action", demand.action);
    }

    let message = match session.status(result).try_into() {
        Ok(message) => message,
        Err(error) => {
            // If we cannot encode the final status message, there is nothing
            // we can do to notify the server, as status is responsible for
            // reporting errors. We can only log the error and carry on.
            error!("failed to encode status message: {}", error);
            return;
        }
    };

    message::send(message);
}

/// Abstraction for various kinds of sessions.
pub trait Session {
    /// Sends a reply to the flow that call the action.
    fn reply<R>(&mut self, response: R) -> Result<()>
    where R: action::Response;

    /// Sends a message to a particular sink.
    fn send<R>(&mut self, sink: Sink, response: R) -> Result<()>
    where R: action::Response;

    /// Sends a heartbeat signal to the Fleetspeak process.
    fn heartbeat(&mut self) {
        // TODO: Create a real implementation.
    }
}

/// A session type for unrequested action executions.
///
/// Certain kind of actions are executed not only when a server flow decides to
/// do so, but also upon particular kind of events (e.g. the agent's startup).
/// In such cases, when one needs to trigger action execution manually, ad-hoc
/// sessions should be used.
pub struct Adhoc;

impl Session for Adhoc {

    // TODO: Session trait should be probably split into two traits and then
    // make the actions that do not care about the `reply` method implement the
    // simpler one.
    fn reply<R>(&mut self, response: R) -> Result<()>
    where
        R: action::Response,
    {
        error!("attempted to reply to an ad-hoc session, dropping response");
        drop(response);

        Ok(())
    }

    fn send<R>(&mut self, sink: Sink, response: R) -> Result<()>
    where
        R: action::Response,
    {
        send(sink.wrap(response))?;

        Ok(())
    }
}

/// A session type for ordinary action requests.
///
/// This is a normal session type that that is associated with some flow on the
/// server. It keeps track of the responses it sends and collects statistics
/// about network and runtime utilization to kill the action if it is needed.
pub struct Action {
    header: Header,
    next_response_id: u64,
}

impl Action {

    /// Constructs a new session for the given `demand` object.
    pub fn from_demand(demand: &Demand) -> Action {
        // Response identifiers that GRR agents use start at 1. Unfortunately,
        // the server uses this assumption (to determine the number of expected
        // responses when status message is received), so we have to follow this
        // behaviour in RRG as well.
        Action {
            header: demand.header.clone(),
            next_response_id: 1,
        }
    }

    /// Wraps an action response to a session-specific response.
    fn wrap<R>(&self, response: R) -> Response<R>
    where
        R: action::Response
    {
        Response {
            session_id: self.header.session_id.clone(),
            request_id: Some(self.header.request_id),
            response_id: Some(self.next_response_id),
            data: response,
        }
    }

    /// Wraps an action result to a session-specific status response.
    ///
    /// Note that this method consumes the session. The reason for this is that
    /// status response should be obtained as the very last response and no
    /// further replies should be possible after that.
    fn status(self, result: Result<()>) -> Status {
        Status {
            session_id: self.header.session_id,
            request_id: self.header.request_id,
            response_id: self.next_response_id,
            result: result,
        }
    }
}

impl Session for Action {

    fn reply<R: action::Response>(&mut self, response: R) -> Result<()> {
        send(self.wrap(response))?;
        self.next_response_id += 1;

        Ok(())
    }

    fn send<R>(&mut self, sink: Sink, response: R) -> Result<()>
    where
        R: action::Response,
    {
        send(sink.wrap(response))?;

        Ok(())
    }
}

/// Sends a session response to the server.
///
/// Note that this function is not exposed on purpose. Actions should send
/// responses through session objects which introduce a layer of safety. `send`
/// is a low-level utility supposed to be used internally.
fn send<R>(response: Response<R>) -> Result<()>
where
    R: action::Response,
{
    let message = response.try_into()?;
    message::send(message);

    Ok(())
}
<|endoftext|>


<commit_before>use russell_lab::{Matrix, Vector};

/// Defines a (bi-linear) Hexahedron with 8 nodes
///
/// The natural coordinates range from -1 to +1 with the geometry centred @ 0
///
/// ```text
///              4________________7
///            ,'|              ,'|
///          ,'  |            ,'  |
///        ,'    |          ,'    |
///      ,'      |        ,'      |
///    5'===============6'        |
///    |         |      |         |
///    |         |      |         |
///    |         0_____ | ________3
///    |       ,'       |       ,'
///    |     ,'         |     ,'
///    |   ,'           |   ,'
///    | ,'             | ,'
///    1________________2'
/// ```
///
/// # Example
///
/// ```
/// // import
/// use gemlab::Hex8;
/// use russell_lab::Vector;
///
/// // geometry object
/// let mut geo = Hex8::new();
/// let ndim = geo.get_ndim();

/// // compute shape fn and deriv @ ksi=(0,0,0) for all nodes
/// let ksi = Vector::new(ndim);
/// geo.calc_shape(&ksi);
/// geo.calc_deriv(&ksi);

/// // get shape fn and deriv for node m
/// let m = 0;
/// let sm = geo.get_shape(m);
/// let mut dsm_dksi = Vector::new(ndim);
/// geo.get_deriv(&mut dsm_dksi, m);

/// // check shape fn and deriv @ ksi for node m
/// assert_eq!(sm, 0.125);
/// assert_eq!(
///     format!("{}", dsm_dksi),
///     "┌        ┐\n\
///      │ -0.125 │\n\
///      │ -0.125 │\n\
///      │ -0.125 │\n\
///      └        ┘"
/// );
/// ```
pub struct Hex8 {
    // natural coordinates (nnode, ndim)
    //
    // ```text
    // ξᵐ = vector{r, s, t} @ node m
    // coords = matrix{ξ⁰, ξ¹, ξ², ξ³, ξ⁴, ξ⁵, ξ⁶, ξ⁷, ξ⁸}
    // ```
    coords: Matrix,

    // shape functions @ natural coordinate (nnode)
    //
    // ```text
    // shape[m](ξ) = Sᵐ(ξ)
    // ```
    shape: Vector,

    // derivatives of shape functions w.r.t natural coordinate (nnode, ndim)
    //
    // ```text
    // deriv[m][i](ξ) = ({dSᵐ(ξ)/dξ}_ξ)[i]
    // ```
    deriv: Matrix,
}

const NDIM: usize = 3;
const NNODE: usize = 8;

impl Hex8 {
    /// Creates a new object with pre-calculated shape fn and derivatives
    pub fn new() -> Self {
        Hex8 {
            #[rustfmt::skip]
            coords: Matrix::from(&[
                [-1.0, -1.0, -1.0],
                [ 1.0, -1.0, -1.0],
                [ 1.0,  1.0, -1.0],
                [-1.0,  1.0, -1.0],
                [-1.0, -1.0,  1.0],
                [ 1.0, -1.0,  1.0],
                [ 1.0,  1.0,  1.0],
                [-1.0,  1.0,  1.0],
            ]),
            shape: Vector::new(NNODE),
            deriv: Matrix::new(NNODE, NDIM),
        }
    }

    /// Calculates the shape functions at natural coordinate
    pub fn calc_shape(&mut self, coord: &Vector) {
        let (r, s, t) = (coord[0], coord[1], coord[2]);

        self.shape[0] = (1.0 - r - s + r * s - t + s * t + r * t - r * s * t) / 8.0;
        self.shape[1] = (1.0 + r - s - r * s - t + s * t - r * t + r * s * t) / 8.0;
        self.shape[2] = (1.0 + r + s + r * s - t - s * t - r * t - r * s * t) / 8.0;
        self.shape[3] = (1.0 - r + s - r * s - t - s * t + r * t + r * s * t) / 8.0;
        self.shape[4] = (1.0 - r - s + r * s + t - s * t - r * t + r * s * t) / 8.0;
        self.shape[5] = (1.0 + r - s - r * s + t - s * t + r * t - r * s * t) / 8.0;
        self.shape[6] = (1.0 + r + s + r * s + t + s * t + r * t + r * s * t) / 8.0;
        self.shape[7] = (1.0 - r + s - r * s + t + s * t - r * t - r * s * t) / 8.0;
    }

    /// Calculates the derivatives of shape functions at natural coordinate
    pub fn calc_deriv(&mut self, coord: &Vector) {
        let (r, s, t) = (coord[0], coord[1], coord[2]);

        self.deriv[0][0] = (-1.0 + s + t - s * t) / 8.0;
        self.deriv[0][1] = (-1.0 + r + t - r * t) / 8.0;
        self.deriv[0][2] = (-1.0 + r + s - r * s) / 8.0;

        self.deriv[1][0] = (1.0 - s - t + s * t) / 8.0;
        self.deriv[1][1] = (-1.0 - r + t + r * t) / 8.0;
        self.deriv[1][2] = (-1.0 - r + s + r * s) / 8.0;

        self.deriv[2][0] = (1.0 + s - t - s * t) / 8.0;
        self.deriv[2][1] = (1.0 + r - t - r * t) / 8.0;
        self.deriv[2][2] = (-1.0 - r - s - r * s) / 8.0;

        self.deriv[3][0] = (-1.0 - s + t + s * t) / 8.0;
        self.deriv[3][1] = (1.0 - r - t + r * t) / 8.0;
        self.deriv[3][2] = (-1.0 + r - s + r * s) / 8.0;

        self.deriv[4][0] = (-1.0 + s - t + s * t) / 8.0;
        self.deriv[4][1] = (-1.0 + r - t + r * t) / 8.0;
        self.deriv[4][2] = (1.0 - r - s + r * s) / 8.0;

        self.deriv[5][0] = (1.0 - s + t - s * t) / 8.0;
        self.deriv[5][1] = (-1.0 - r - t - r * t) / 8.0;
        self.deriv[5][2] = (1.0 + r - s - r * s) / 8.0;

        self.deriv[6][0] = (1.0 + s + t + s * t) / 8.0;
        self.deriv[6][1] = (1.0 + r + t + r * t) / 8.0;
        self.deriv[6][2] = (1.0 + r + s + r * s) / 8.0;

        self.deriv[7][0] = (-1.0 - s - t - s * t) / 8.0;
        self.deriv[7][1] = (1.0 - r + t - r * t) / 8.0;
        self.deriv[7][2] = (1.0 - r + s - r * s) / 8.0;
    }

    /// Returns the previously computed shape function for node m
    pub fn get_shape(&self, m: usize) -> f64 {
        self.shape[m]
    }

    /// Returns the previously computed derivative of shape function for node m
    pub fn get_deriv(&self, deriv: &mut Vector, m: usize) {
        deriv[0] = self.deriv[m][0];
        deriv[1] = self.deriv[m][1];
        deriv[2] = self.deriv[m][2];
    }

    /// Returns the number of dimensions
    pub fn get_ndim(&self) -> usize {
        NDIM
    }

    /// Returns the number of nodes
    pub fn get_nnode(&self) -> usize {
        NNODE
    }

    /// Returns the natural coordinates @ node m
    pub fn get_coord(&self, coord: &mut Vector, m: usize) {
        coord[0] = self.coords[m][0];
        coord[1] = self.coords[m][1];
        coord[2] = self.coords[m][2];
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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

    // Holds arguments for numerical differentiation
    struct Arguments {
        geo: Hex8,      // geometry
        at_ksi: Vector, // at nat coord value
        ksi: Vector,    // temporary nat coord
        m: usize,       // shape: node index
        i: usize,       // nat coord: dimension index
    }

    // Computes the shape function @ m as a function of x = ksi[i]
    fn sm(x: f64, args: &mut Arguments) -> f64 {
        args.ksi[0] = args.at_ksi[0];
        args.ksi[1] = args.at_ksi[1];
        args.ksi[2] = args.at_ksi[2];
        args.ksi[args.i] = x;
        args.geo.calc_shape(&args.ksi);
        args.geo.get_shape(args.m)
    }

    #[test]
    fn new_works() {
        let geo = Hex8::new();
        assert_eq!(geo.coords.dims(), (NNODE, NDIM));
        assert_eq!(geo.shape.dim(), NNODE);
        assert_eq!(geo.deriv.dims(), (NNODE, NDIM));
    }

    #[test]
    fn calc_shape_works() {
        let mut geo = Hex8::new();
        let mut ksi = Vector::new(NDIM);
        for m in 0..NNODE {
            geo.get_coord(&mut ksi, m);
            geo.calc_shape(&ksi);
            for n in 0..NNODE {
                let smn = geo.get_shape(n);
                if m == n {
                    assert_approx_eq!(smn, 1.0, 1e-15);
                } else {
                    assert_approx_eq!(smn, 0.0, 1e-15);
                }
            }
        }
    }

    #[test]
    fn calc_deriv_works() {
        let args = &mut Arguments {
            geo: Hex8::new(),
            at_ksi: Vector::from(&[0.25, 0.25, 0.25]),
            ksi: Vector::new(NDIM),
            m: 0,
            i: 0,
        };
        let mut geo = Hex8::new();
        let mut dsm_dksi = Vector::new(NDIM);
        geo.calc_deriv(&args.at_ksi);
        for m in 0..NNODE {
            geo.get_deriv(&mut dsm_dksi, m);
            args.m = m;
            for i in 0..NDIM {
                args.i = i;
                assert_deriv_approx_eq!(dsm_dksi[i], args.at_ksi[i], sm, args, 1e-13);
            }
        }
    }

    #[test]
    fn getters_work() {
        let geo = Hex8::new();
        assert_eq!(geo.get_ndim(), NDIM);
        assert_eq!(geo.get_nnode(), NNODE);
    }

    #[test]
    fn another() {}
}
<commit_msg>Use Vec of Vector for nat coords<commit_after>use russell_lab::{Matrix, Vector};

/// Defines a (bi-linear) Hexahedron with 8 nodes
///
/// The natural coordinates range from -1 to +1 with the geometry centred @ 0
///
/// ```text
///              4________________7
///            ,'|              ,'|
///          ,'  |            ,'  |
///        ,'    |          ,'    |
///      ,'      |        ,'      |
///    5'===============6'        |
///    |         |      |         |
///    |         |      |         |
///    |         0_____ | ________3
///    |       ,'       |       ,'
///    |     ,'         |     ,'
///    |   ,'           |   ,'
///    | ,'             | ,'
///    1________________2'
/// ```
///
/// # Example
///
/// ```
/// // import
/// use gemlab::Hex8;
/// use russell_lab::Vector;
///
/// // geometry object
/// let mut geo = Hex8::new();
/// let ndim = geo.get_ndim();

/// // compute shape fn and deriv @ ksi=(0,0,0) for all nodes
/// let ksi = Vector::new(ndim);
/// geo.calc_shape(&ksi);
/// geo.calc_deriv(&ksi);

/// // get shape fn and deriv for node m
/// let m = 0;
/// let sm = geo.get_shape(m);
/// let mut dsm_dksi = Vector::new(ndim);
/// geo.get_deriv(&mut dsm_dksi, m);

/// // check shape fn and deriv @ ksi for node m
/// assert_eq!(sm, 0.125);
/// assert_eq!(
///     format!("{}", dsm_dksi),
///     "┌        ┐\n\
///      │ -0.125 │\n\
///      │ -0.125 │\n\
///      │ -0.125 │\n\
///      └        ┘"
/// );
/// ```
pub struct Hex8 {
    // natural coordinates (nnode, ndim)
    //
    // ```text
    // ξᵐ = vector{r, s, t} @ node m
    // coords = [ξ⁰, ξ¹, ξ², ξ³, ξ⁴, ξ⁵, ξ⁶, ξ⁷, ξ⁸]
    // ```
    coords: Vec<Vector>,

    // shape functions @ natural coordinate (nnode)
    //
    // ```text
    // shape[m](ξ) = Sᵐ(ξ)
    // ```
    shape: Vector,

    // derivatives of shape functions w.r.t natural coordinate (nnode, ndim)
    //
    // ```text
    // deriv[m][i](ξ) = ({dSᵐ(ξ)/dξ}_ξ)[i]
    // ```
    deriv: Matrix,
}

const NDIM: usize = 3;
const NNODE: usize = 8;

impl Hex8 {
    /// Creates a new object with pre-calculated shape fn and derivatives
    pub fn new() -> Self {
        Hex8 {
            #[rustfmt::skip]
            coords: vec![
                Vector::from(&[-1.0, -1.0, -1.0]),
                Vector::from(&[ 1.0, -1.0, -1.0]),
                Vector::from(&[ 1.0,  1.0, -1.0]),
                Vector::from(&[-1.0,  1.0, -1.0]),
                Vector::from(&[-1.0, -1.0,  1.0]),
                Vector::from(&[ 1.0, -1.0,  1.0]),
                Vector::from(&[ 1.0,  1.0,  1.0]),
                Vector::from(&[-1.0,  1.0,  1.0]),
            ],
            shape: Vector::new(NNODE),
            deriv: Matrix::new(NNODE, NDIM),
        }
    }

    /// Calculates the shape functions at natural coordinate
    pub fn calc_shape(&mut self, coord: &Vector) {
        let (r, s, t) = (coord[0], coord[1], coord[2]);

        self.shape[0] = (1.0 - r - s + r * s - t + s * t + r * t - r * s * t) / 8.0;
        self.shape[1] = (1.0 + r - s - r * s - t + s * t - r * t + r * s * t) / 8.0;
        self.shape[2] = (1.0 + r + s + r * s - t - s * t - r * t - r * s * t) / 8.0;
        self.shape[3] = (1.0 - r + s - r * s - t - s * t + r * t + r * s * t) / 8.0;
        self.shape[4] = (1.0 - r - s + r * s + t - s * t - r * t + r * s * t) / 8.0;
        self.shape[5] = (1.0 + r - s - r * s + t - s * t + r * t - r * s * t) / 8.0;
        self.shape[6] = (1.0 + r + s + r * s + t + s * t + r * t + r * s * t) / 8.0;
        self.shape[7] = (1.0 - r + s - r * s + t + s * t - r * t - r * s * t) / 8.0;
    }

    /// Calculates the derivatives of shape functions at natural coordinate
    pub fn calc_deriv(&mut self, coord: &Vector) {
        let (r, s, t) = (coord[0], coord[1], coord[2]);

        self.deriv[0][0] = (-1.0 + s + t - s * t) / 8.0;
        self.deriv[0][1] = (-1.0 + r + t - r * t) / 8.0;
        self.deriv[0][2] = (-1.0 + r + s - r * s) / 8.0;

        self.deriv[1][0] = (1.0 - s - t + s * t) / 8.0;
        self.deriv[1][1] = (-1.0 - r + t + r * t) / 8.0;
        self.deriv[1][2] = (-1.0 - r + s + r * s) / 8.0;

        self.deriv[2][0] = (1.0 + s - t - s * t) / 8.0;
        self.deriv[2][1] = (1.0 + r - t - r * t) / 8.0;
        self.deriv[2][2] = (-1.0 - r - s - r * s) / 8.0;

        self.deriv[3][0] = (-1.0 - s + t + s * t) / 8.0;
        self.deriv[3][1] = (1.0 - r - t + r * t) / 8.0;
        self.deriv[3][2] = (-1.0 + r - s + r * s) / 8.0;

        self.deriv[4][0] = (-1.0 + s - t + s * t) / 8.0;
        self.deriv[4][1] = (-1.0 + r - t + r * t) / 8.0;
        self.deriv[4][2] = (1.0 - r - s + r * s) / 8.0;

        self.deriv[5][0] = (1.0 - s + t - s * t) / 8.0;
        self.deriv[5][1] = (-1.0 - r - t - r * t) / 8.0;
        self.deriv[5][2] = (1.0 + r - s - r * s) / 8.0;

        self.deriv[6][0] = (1.0 + s + t + s * t) / 8.0;
        self.deriv[6][1] = (1.0 + r + t + r * t) / 8.0;
        self.deriv[6][2] = (1.0 + r + s + r * s) / 8.0;

        self.deriv[7][0] = (-1.0 - s - t - s * t) / 8.0;
        self.deriv[7][1] = (1.0 - r + t - r * t) / 8.0;
        self.deriv[7][2] = (1.0 - r + s - r * s) / 8.0;
    }

    /// Returns the previously computed shape function for node m
    pub fn get_shape(&self, m: usize) -> f64 {
        self.shape[m]
    }

    /// Returns the previously computed derivative of shape function for node m
    pub fn get_deriv(&self, deriv: &mut Vector, m: usize) {
        deriv[0] = self.deriv[m][0];
        deriv[1] = self.deriv[m][1];
        deriv[2] = self.deriv[m][2];
    }

    /// Returns the number of dimensions
    pub fn get_ndim(&self) -> usize {
        NDIM
    }

    /// Returns the number of nodes
    pub fn get_nnode(&self) -> usize {
        NNODE
    }

    /// Returns the natural coordinates @ node m
    pub fn get_coord(&self, coord: &mut Vector, m: usize) {
        coord[0] = self.coords[m][0];
        coord[1] = self.coords[m][1];
        coord[2] = self.coords[m][2];
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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

    // Holds arguments for numerical differentiation
    struct Arguments {
        geo: Hex8,      // geometry
        at_ksi: Vector, // at nat coord value
        ksi: Vector,    // temporary nat coord
        m: usize,       // shape: node index
        i: usize,       // nat coord: dimension index
    }

    // Computes the shape function @ m as a function of x = ksi[i]
    fn sm(x: f64, args: &mut Arguments) -> f64 {
        args.ksi[0] = args.at_ksi[0];
        args.ksi[1] = args.at_ksi[1];
        args.ksi[2] = args.at_ksi[2];
        args.ksi[args.i] = x;
        args.geo.calc_shape(&args.ksi);
        args.geo.get_shape(args.m)
    }

    #[test]
    fn new_works() {
        let geo = Hex8::new();
        assert_eq!(geo.coords.len(), NNODE);
        assert_eq!(geo.shape.dim(), NNODE);
        assert_eq!(geo.deriv.dims(), (NNODE, NDIM));
    }

    #[test]
    fn calc_shape_works() {
        let mut geo = Hex8::new();
        let mut ksi = Vector::new(NDIM);
        for m in 0..NNODE {
            geo.get_coord(&mut ksi, m);
            geo.calc_shape(&ksi);
            for n in 0..NNODE {
                let smn = geo.get_shape(n);
                if m == n {
                    assert_approx_eq!(smn, 1.0, 1e-15);
                } else {
                    assert_approx_eq!(smn, 0.0, 1e-15);
                }
            }
        }
    }

    #[test]
    fn calc_deriv_works() {
        let args = &mut Arguments {
            geo: Hex8::new(),
            at_ksi: Vector::from(&[0.25, 0.25, 0.25]),
            ksi: Vector::new(NDIM),
            m: 0,
            i: 0,
        };
        let mut geo = Hex8::new();
        let mut dsm_dksi = Vector::new(NDIM);
        geo.calc_deriv(&args.at_ksi);
        for m in 0..NNODE {
            geo.get_deriv(&mut dsm_dksi, m);
            args.m = m;
            for i in 0..NDIM {
                args.i = i;
                assert_deriv_approx_eq!(dsm_dksi[i], args.at_ksi[i], sm, args, 1e-13);
            }
        }
    }

    #[test]
    fn getters_work() {
        let geo = Hex8::new();
        assert_eq!(geo.get_ndim(), NDIM);
        assert_eq!(geo.get_nnode(), NNODE);
    }

    #[test]
    fn another() {}
}
<|endoftext|>


<commit_before>//! This module provides the interface to different solvers.
//!
//! Both [`coin_cbc`](https://docs.rs/coin_cbc/latest/coin_cbc/) and
//! [`minilp`](https://docs.rs/minilp/0.2.2/minilp/) are available as cargo
//! [features](https://doc.rust-lang.org/cargo/reference/features.html). To use
//! them, specify your dependency to `lp_modeler` accordingly in your `Cargo.toml`
//! (note the difference in name with the `native_coin_cbc` feature for `coin_cbc`):
//! ```ignore
//! [dependencies.lp_modeler]
//! version = "4.3"
//! features = "native_coin_cbc"
//! ```
//! or:
//! ```ignore
//! [dependencies.lp_modeler]
//! version = "4.3"
//! features = "minilp"
//! ```
//!
//! The other solvers need to be installed externally on your system.
//! The respective information is provided in the project's README in the section on
//! [installing external solvers](https://github.com/jcavat/rust-lp-modeler#installing-external-solvers).

use std::collections::HashMap;

use dsl::{Problem, LpContinuous, LpBinary, LpInteger, LpProblem, LpExprNode, LpExprOp, LpExprArenaIndex};

pub mod cbc;
pub use self::cbc::*;

pub mod gurobi;
pub use self::gurobi::*;

pub mod glpk;
pub use self::glpk::*;

#[cfg(feature = "minilp")]
pub mod minilp;
#[cfg(feature = "minilp")]
pub use self::minilp::*;

#[cfg(feature = "native_coin_cbc")]
pub mod native_cbc;
#[cfg(feature = "native_coin_cbc")]
pub use self::native_cbc::*;

use std::fs::File;
use std::fs;
use util::is_zero;

#[derive(Debug, PartialEq, Clone)]
pub enum Status {
    Optimal,
    SubOptimal,
    Infeasible,
    Unbounded,
    NotSolved,
}

#[derive(Debug, Clone)]
pub struct Solution<'a> {
    pub status: Status,
    pub results: HashMap<String, f32>,
    pub related_problem: Option<&'a LpProblem>
}
impl Solution<'_> {
    pub fn new<'a>(status: Status, results: HashMap<String, f32>) -> Solution<'a> {
        Solution {
            status,
            results,
            related_problem: None
        }
    }
    pub fn with_problem(status: Status, results: HashMap<String, f32>, problem: &LpProblem) -> Solution {
        Solution {
            status,
            results,
            related_problem: Some(problem)
        }
    }
    fn check_possible_solution(&self) {
        match &self.status {
            Status::Unbounded | Status::NotSolved | Status::Infeasible => panic!("Solution must be optimal or suboptimal"),
            _ => ()
        }
    }
    pub fn get_raw_value(&self, name: &str) -> f32 {
        self.check_possible_solution();
        *self.results.get(name).expect("No value found for this variable. Check if the variable has been used in the related problem.")
    }
    pub fn get_bool(&self, var: &LpBinary) -> bool {
        self.check_possible_solution();
        self.results.get(&var.name).and_then(|&f| if is_zero(1.0-f) { Some(true) } else if is_zero(f) { Some(false) } else { None } ).expect("Result value cannot be interpreted as boolean")
    }
    pub fn get_float(&self, var: &LpContinuous) -> f32 {
        self.check_possible_solution();
        *self.results.get(&var.name).expect("No value found for this variable. Check if the variable has been used in the related problem.")
    }
    pub fn get_int(&self, var: &LpInteger) -> i32 {
        self.check_possible_solution();
        let &f = self.results.get(&var.name).expect("No value found for this variable. Check if the variable has been used in the related problem.");
        let i = f as i32;
        assert!( is_zero( f-(i as f32)), format!("Value {} cannot be interpreted as integer.", f) );
        i
    }
    pub fn eval(&self) -> Option<f32> {
        self.related_problem
            .and_then( |problem| {
                match &problem.obj_expr_arena {
                    Some(obj_expr_arena) => Some( self.eval_with(&obj_expr_arena.get_root_index(), &self.results) ),
                    None => None
                }
            })
    }
    fn eval_with(&self, index: &LpExprArenaIndex, values: &HashMap<String, f32>) -> f32 {
        match self.related_problem.unwrap().obj_expr_arena.as_ref().unwrap().expr_ref_at(*index) {
            LpExprNode::LpCompExpr(operation, left, right) => {
                match operation {
                    LpExprOp::Addition => self.eval_with(left, values) + self.eval_with(right, values),
                    LpExprOp::Multiplication => self.eval_with(left, values) * self.eval_with(right, values),
                    LpExprOp::Subtraction => self.eval_with(left, values) - self.eval_with(right, values),
                }
            },
            LpExprNode::ConsBin(LpBinary { name })
            | LpExprNode::ConsCont(LpContinuous { name, .. })
            | LpExprNode::ConsInt(LpInteger { name, .. }) => *values.get(name).unwrap_or(&0f32),
            LpExprNode::LitVal(n) => *n,
            LpExprNode::EmptyExpr => 0.0
        }
    }
}

pub trait SolverTrait {
    type P: Problem;
    fn run<'a>(&self, problem: &'a Self::P) -> Result<Solution<'a>, String>;
}

pub trait SolverWithSolutionParsing {
    fn read_solution<'a>(&self, temp_solution_file: &String, problem: Option<&'a LpProblem>) -> Result<Solution<'a>, String> {
        match File::open( temp_solution_file ) {
            Ok(f) => {
                let res = self.read_specific_solution(&f, problem)?;
                let _ = fs::remove_file(temp_solution_file);
                Ok(res)
            }
            Err(_) => return Err("Cannot open file".to_string()),
        }
    }
    fn read_specific_solution<'a>(&self, f: &File, problem: Option<&'a LpProblem>) -> Result<Solution<'a>, String>;
}

pub trait WithMaxSeconds<T> {
    fn max_seconds(&self) -> Option<u32>;
    fn with_max_seconds(&self, seconds: u32) -> T;
}

pub trait WithNbThreads<T> {
    fn nb_threads(&self) -> Option<u32>;
    fn with_nb_threads(&self, threads: u32) -> T;
}
<commit_msg>src/solvers module doc comment<commit_after>//! This module provides the interface to different solvers.
//!
//! Both [`coin_cbc`](https://docs.rs/coin_cbc/latest/coin_cbc/) and
//! [`minilp`](https://docs.rs/minilp/0.2.2/minilp/) are available as cargo
//! [features](https://doc.rust-lang.org/cargo/reference/features.html). To use
//! them, specify your dependency to `lp_modeler` accordingly in your `Cargo.toml`
//! (note the name difference of the `native_coin_cbc` feature for the `coin_cbc` crate):
//! ```ignore
//! [dependencies.lp_modeler]
//! version = "4.3"
//! features = "native_coin_cbc"
//! ```
//! or:
//! ```ignore
//! [dependencies.lp_modeler]
//! version = "4.3"
//! features = "minilp"
//! ```
//! For `coin_cbc` to compile, the `Cbc` library files need to be available on your system.
//! See the [`coin_cbc` project README](https://github.com/KardinalAI/coin_cbc) for more infos.
//!
//! The other solvers need to be installed externally on your system.
//! The respective information is provided in the project's README in the section on
//! [installing external solvers](https://github.com/jcavat/rust-lp-modeler#installing-external-solvers).

use std::collections::HashMap;

use dsl::{Problem, LpContinuous, LpBinary, LpInteger, LpProblem, LpExprNode, LpExprOp, LpExprArenaIndex};

pub mod cbc;
pub use self::cbc::*;

pub mod gurobi;
pub use self::gurobi::*;

pub mod glpk;
pub use self::glpk::*;

#[cfg(feature = "minilp")]
pub mod minilp;
#[cfg(feature = "minilp")]
pub use self::minilp::*;

#[cfg(feature = "native_coin_cbc")]
pub mod native_cbc;
#[cfg(feature = "native_coin_cbc")]
pub use self::native_cbc::*;

use std::fs::File;
use std::fs;
use util::is_zero;

#[derive(Debug, PartialEq, Clone)]
pub enum Status {
    Optimal,
    SubOptimal,
    Infeasible,
    Unbounded,
    NotSolved,
}

#[derive(Debug, Clone)]
pub struct Solution<'a> {
    pub status: Status,
    pub results: HashMap<String, f32>,
    pub related_problem: Option<&'a LpProblem>
}
impl Solution<'_> {
    pub fn new<'a>(status: Status, results: HashMap<String, f32>) -> Solution<'a> {
        Solution {
            status,
            results,
            related_problem: None
        }
    }
    pub fn with_problem(status: Status, results: HashMap<String, f32>, problem: &LpProblem) -> Solution {
        Solution {
            status,
            results,
            related_problem: Some(problem)
        }
    }
    fn check_possible_solution(&self) {
        match &self.status {
            Status::Unbounded | Status::NotSolved | Status::Infeasible => panic!("Solution must be optimal or suboptimal"),
            _ => ()
        }
    }
    pub fn get_raw_value(&self, name: &str) -> f32 {
        self.check_possible_solution();
        *self.results.get(name).expect("No value found for this variable. Check if the variable has been used in the related problem.")
    }
    pub fn get_bool(&self, var: &LpBinary) -> bool {
        self.check_possible_solution();
        self.results.get(&var.name).and_then(|&f| if is_zero(1.0-f) { Some(true) } else if is_zero(f) { Some(false) } else { None } ).expect("Result value cannot be interpreted as boolean")
    }
    pub fn get_float(&self, var: &LpContinuous) -> f32 {
        self.check_possible_solution();
        *self.results.get(&var.name).expect("No value found for this variable. Check if the variable has been used in the related problem.")
    }
    pub fn get_int(&self, var: &LpInteger) -> i32 {
        self.check_possible_solution();
        let &f = self.results.get(&var.name).expect("No value found for this variable. Check if the variable has been used in the related problem.");
        let i = f as i32;
        assert!( is_zero( f-(i as f32)), format!("Value {} cannot be interpreted as integer.", f) );
        i
    }
    pub fn eval(&self) -> Option<f32> {
        self.related_problem
            .and_then( |problem| {
                match &problem.obj_expr_arena {
                    Some(obj_expr_arena) => Some( self.eval_with(&obj_expr_arena.get_root_index(), &self.results) ),
                    None => None
                }
            })
    }
    fn eval_with(&self, index: &LpExprArenaIndex, values: &HashMap<String, f32>) -> f32 {
        match self.related_problem.unwrap().obj_expr_arena.as_ref().unwrap().expr_ref_at(*index) {
            LpExprNode::LpCompExpr(operation, left, right) => {
                match operation {
                    LpExprOp::Addition => self.eval_with(left, values) + self.eval_with(right, values),
                    LpExprOp::Multiplication => self.eval_with(left, values) * self.eval_with(right, values),
                    LpExprOp::Subtraction => self.eval_with(left, values) - self.eval_with(right, values),
                }
            },
            LpExprNode::ConsBin(LpBinary { name })
            | LpExprNode::ConsCont(LpContinuous { name, .. })
            | LpExprNode::ConsInt(LpInteger { name, .. }) => *values.get(name).unwrap_or(&0f32),
            LpExprNode::LitVal(n) => *n,
            LpExprNode::EmptyExpr => 0.0
        }
    }
}

pub trait SolverTrait {
    type P: Problem;
    fn run<'a>(&self, problem: &'a Self::P) -> Result<Solution<'a>, String>;
}

pub trait SolverWithSolutionParsing {
    fn read_solution<'a>(&self, temp_solution_file: &String, problem: Option<&'a LpProblem>) -> Result<Solution<'a>, String> {
        match File::open( temp_solution_file ) {
            Ok(f) => {
                let res = self.read_specific_solution(&f, problem)?;
                let _ = fs::remove_file(temp_solution_file);
                Ok(res)
            }
            Err(_) => return Err("Cannot open file".to_string()),
        }
    }
    fn read_specific_solution<'a>(&self, f: &File, problem: Option<&'a LpProblem>) -> Result<Solution<'a>, String>;
}

pub trait WithMaxSeconds<T> {
    fn max_seconds(&self) -> Option<u32>;
    fn with_max_seconds(&self, seconds: u32) -> T;
}

pub trait WithNbThreads<T> {
    fn nb_threads(&self) -> Option<u32>;
    fn with_nb_threads(&self, threads: u32) -> T;
}
<|endoftext|>


<commit_before>// Copyright (C) 2020, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use crate::Error;
use crate::Result;

use std::collections::VecDeque;

/// Keeps track of DATAGRAM frames.
#[derive(Default)]
pub struct DatagramQueue {
    queue: VecDeque<Vec<u8>>,
    queue_max_len: usize,
    queue_bytes_size: usize,
}

impl DatagramQueue {
    pub fn new(queue_max_len: usize) -> Self {
        DatagramQueue {
            queue: VecDeque::with_capacity(queue_max_len),
            queue_bytes_size: 0,
            queue_max_len,
        }
    }

    pub fn push(&mut self, data: Vec<u8>) -> Result<()> {
        if self.is_full() {
            return Err(Error::Done);
        }

        self.queue_bytes_size += data.len();
        self.queue.push_back(data);

        Ok(())
    }

    pub fn peek_front_len(&self) -> Option<usize> {
        self.queue.front().map(|d| d.len())
    }

    pub fn peek_front_bytes(&self, buf: &mut [u8], len: usize) -> Result<usize> {
        match self.queue.front() {
            Some(d) => {
                let len = std::cmp::min(len, d.len());
                if buf.len() < len {
                    return Err(Error::BufferTooShort);
                }

                buf[..len].copy_from_slice(&d[..len]);
                Ok(len)
            },

            None => Err(Error::Done),
        }
    }

    pub fn pop(&mut self) -> Option<Vec<u8>> {
        if let Some(d) = self.queue.pop_front() {
            self.queue_bytes_size = self.queue_bytes_size.saturating_sub(d.len());
            return Some(d);
        }

        None
    }

    pub fn has_pending(&self) -> bool {
        !self.queue.is_empty()
    }

    pub fn purge<F: Fn(&[u8]) -> bool>(&mut self, f: F) {
        self.queue.retain(|d| !f(d));
        self.queue_bytes_size =
            self.queue.iter().fold(0, |total, d| total + d.len());
    }

    pub fn is_full(&self) -> bool {
        self.queue.len() == self.queue_max_len
    }

    pub fn len(&self) -> usize {
        self.queue.len()
    }

    pub fn byte_size(&self) -> usize {
        self.queue_bytes_size
    }
}
<commit_msg>dgram: don't allocate full queue upfront<commit_after>// Copyright (C) 2020, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use crate::Error;
use crate::Result;

use std::collections::VecDeque;

const DGRAM_QUEUE_DEFAULT_LEN: usize = 256;

/// Keeps track of DATAGRAM frames.
#[derive(Default)]
pub struct DatagramQueue {
    queue: VecDeque<Vec<u8>>,
    queue_max_len: usize,
    queue_bytes_size: usize,
}

impl DatagramQueue {
    pub fn new(queue_max_len: usize) -> Self {
        DatagramQueue {
            queue: VecDeque::with_capacity(
                DGRAM_QUEUE_DEFAULT_LEN.min(queue_max_len),
            ),
            queue_bytes_size: 0,
            queue_max_len,
        }
    }

    pub fn push(&mut self, data: Vec<u8>) -> Result<()> {
        if self.is_full() {
            return Err(Error::Done);
        }

        self.queue_bytes_size += data.len();
        self.queue.push_back(data);

        Ok(())
    }

    pub fn peek_front_len(&self) -> Option<usize> {
        self.queue.front().map(|d| d.len())
    }

    pub fn peek_front_bytes(&self, buf: &mut [u8], len: usize) -> Result<usize> {
        match self.queue.front() {
            Some(d) => {
                let len = std::cmp::min(len, d.len());
                if buf.len() < len {
                    return Err(Error::BufferTooShort);
                }

                buf[..len].copy_from_slice(&d[..len]);
                Ok(len)
            },

            None => Err(Error::Done),
        }
    }

    pub fn pop(&mut self) -> Option<Vec<u8>> {
        if let Some(d) = self.queue.pop_front() {
            self.queue_bytes_size = self.queue_bytes_size.saturating_sub(d.len());
            return Some(d);
        }

        None
    }

    pub fn has_pending(&self) -> bool {
        !self.queue.is_empty()
    }

    pub fn purge<F: Fn(&[u8]) -> bool>(&mut self, f: F) {
        self.queue.retain(|d| !f(d));
        self.queue_bytes_size =
            self.queue.iter().fold(0, |total, d| total + d.len());
    }

    pub fn is_full(&self) -> bool {
        self.queue.len() == self.queue_max_len
    }

    pub fn len(&self) -> usize {
        self.queue.len()
    }

    pub fn byte_size(&self) -> usize {
        self.queue_bytes_size
    }
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! A tree stream is the result of annotating an annotated stream. This forms a tree structure with the original input
//! stream at the leaves.
//!

use super::countable::*;
use super::annotated_stream::*;

///
/// Represents a stream that has been decomposed into a tree
///
#[derive(Clone)]
pub struct TreeStream<InputSymbol, TokenType> {
    /// How the original input stream maps onto tokens
    tokens: AnnotatedStream<InputSymbol, TokenType>,

    /// The hierarchy of annotations. As a tree, the 'root' is considered to be the last entry in this list (it's built from the bottom up)
    annotations: Vec<AnnotatedStream<TokenType, TokenType>>
}

impl<InputSymbol: Clone+Ord+Countable, TokenType: Clone+Ord+'static> TreeStream<InputSymbol, TokenType> {
    ///
    /// Creates a new tree stream from a tokenized stream
    ///
    pub fn new_with_tokens(tokens: AnnotatedStream<InputSymbol, TokenType>) -> Self {
        TreeStream { tokens: tokens, annotations: vec![] }
    }
}
<commit_msg>Start working on the API for the tokenized tree: need a way to read the base input<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! A tree stream is the result of annotating an annotated stream. This forms a tree structure with the original input
//! stream at the leaves.
//!

use super::countable::*;
use super::symbol_reader::*;
use super::annotated_stream::*;

///
/// Represents a stream that has been decomposed into a tree
///
#[derive(Clone)]
pub struct TreeStream<InputSymbol, TokenType> {
    /// How the original input stream maps onto tokens
    tokens: AnnotatedStream<InputSymbol, TokenType>,

    /// The hierarchy of annotations. As a tree, the 'root' is considered to be the last entry in this list (it's built from the bottom up)
    annotations: Vec<AnnotatedStream<TokenType, TokenType>>
}

impl<InputSymbol: Clone+Ord+Countable, TokenType: Clone+Ord+'static> TreeStream<InputSymbol, TokenType> {
    ///
    /// Creates a new tree stream from a tokenized stream
    ///
    pub fn new_with_tokens(tokens: AnnotatedStream<InputSymbol, TokenType>) -> Self {
        TreeStream { tokens: tokens, annotations: vec![] }
    }

    ///
    /// Reads the input that made up this tree stream
    ///
    pub fn read_input<'a>(&'a self) -> Box<SymbolReader<InputSymbol>+'a> {
        self.tokens.read_input()
    }
}

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

    #[derive(Ord, PartialOrd, Eq, PartialEq, Clone)]
    enum TestToken {
        Digit,
        Identifier,
        Whitespace
    }

    fn create_simple_tokenizer() -> SymbolRangeDfa<char, TestToken> {
        let mut token_matcher = TokenMatcher::new();

        token_matcher.add_pattern(MatchRange('0', '9').repeat_forever(1), TestToken::Digit);
        token_matcher.add_pattern(MatchRange('a', 'z').repeat_forever(1), TestToken::Identifier);
        token_matcher.add_pattern(" ".repeat_forever(1), TestToken::Whitespace);

        token_matcher.prepare_to_match()
    }

    #[test]
    pub fn can_iterate_over_base_stream() {
        let tokenizer        = create_simple_tokenizer();
        let tokenized_stream = AnnotatedStream::from_tokenizer(&tokenizer, &mut "a+1".read_symbols());
        let tokenized_tree   = TreeStream::new_with_tokens(tokenized_stream);

        assert!(tokenized_tree.read_input().to_vec() == vec!['a', '+', '1']);
    }
}
<|endoftext|>


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

use gdk::{EventKey, CONTROL_MASK, MOD1_MASK};
use gdk::enums::key::{Escape, Tab, ISO_Left_Tab};
use gtk::Inhibit;
use mg_settings::{self, EnumFromStr, EnumMetaData, SettingCompletion, SpecialCommand};
use mg_settings::key::Key;
use relm::Widget;

use app::{Mg, Msg, BLOCKING_INPUT_MODE, COMMAND_MODE, INPUT_MODE, NORMAL_MODE};
use app::ShortcutCommand::{Complete, Incomplete};
use key_converter::gdk_key_to_key;

/// Convert a shortcut of keys to a `String`.
pub fn shortcut_to_string(keys: &[Key]) -> String {
    let strings: Vec<_> = keys.iter().map(ToString::to_string).collect();
    strings.join("")
}

impl<COMM, SETT> Mg<COMM, SETT>
    where COMM: Clone + EnumFromStr + EnumMetaData + SpecialCommand + 'static,
          SETT: Default + EnumMetaData + mg_settings::settings::Settings + SettingCompletion + 'static,
{
    /// Add the key to the current shortcut.
    pub fn add_to_shortcut(&mut self, key: Key) {
        self.model.current_shortcut.push(key);
        self.update_shortcut_label();
    }

    /// Clear the current shortcut buffer.
    pub fn clear_shortcut(&mut self) {
        self.model.current_shortcut.clear();
        self.update_shortcut_label();
    }

    /// Handle a possible input of a shortcut.
    pub fn handle_shortcut(&mut self, key: &EventKey) -> (Option<Msg<COMM, SETT>>, Inhibit) {
        let keyval = key.get_keyval();
        // TODO: refactor this to only inhibit shortcuts found in the config file.
        let alt_pressed = key.get_state() & MOD1_MASK == MOD1_MASK;
        let control_pressed = key.get_state() & CONTROL_MASK == CONTROL_MASK;
        let mut should_inhibit = self.model.current_mode == NORMAL_MODE ||
            (self.model.current_mode == COMMAND_MODE && (keyval == Tab || keyval == ISO_Left_Tab || control_pressed)) ||
            key.get_keyval() == Escape;
        if !self.model.entry_shown || alt_pressed || control_pressed || keyval == Tab || keyval == ISO_Left_Tab {
            if let Some(key) = gdk_key_to_key(key) {
                self.add_to_shortcut(key);
                let action = {
                    let mut current_mode = self.model.current_mode.clone();
                    // The input modes have the same mappings as the command mode.
                    if current_mode == INPUT_MODE || current_mode == BLOCKING_INPUT_MODE {
                        current_mode = COMMAND_MODE.to_string();
                    }
                    self.model.mappings.get(&current_mode.as_ref())
                        .and_then(|mappings| mappings.get(&self.model.current_shortcut).cloned())
                };
                if let Some(action) = action {
                    // FIXME: this is copied a couple of lines below.
                    if !self.model.entry_shown {
                        self.reset();
                    }
                    self.clear_shortcut();
                    match self.action_to_command(&action) {
                        Complete(command) => return (self.handle_command(Some(command)), Inhibit(should_inhibit)),
                        Incomplete(command) => {
                            self.input_command(&command);
                            //self.status_bar.show_completion();
                            //self.update_completions();
                            should_inhibit = true;
                        },
                    }
                }
                else if self.no_possible_shortcut() {
                    if !self.model.entry_shown {
                        self.reset();
                    }
                    self.clear_shortcut();
                }
            }
        }
        (None, Inhibit(should_inhibit))
    }

    /// Check if there are no possible shortcuts.
    fn no_possible_shortcut(&self) -> bool {
        if let Some(mappings) = self.model.mappings.get(&self.model.current_mode.as_ref()) {
            for key in mappings.keys() {
                if key.starts_with(&self.model.current_shortcut) {
                    return false;
                }
            }
        }
        true
    }

    // TODO: remove this when updating the model in methods outside the trait will update the view.
    /// Update the shortcut label.
    fn update_shortcut_label(&self) {
        self.shortcut.widget().root().set_text(&shortcut_to_string(&self.model.current_shortcut));
    }
}

/*impl<Spec, Comm, Sett> Application<Comm, Sett, Spec>
    where Spec: SpecialCommand + 'static,
          Comm: EnumFromStr + EnumMetaData + 'static,
          Sett: mg_settings::settings::Settings + EnumMetaData + SettingCompletion + 'static,
{
    /// Handle a shortcut in input mode.
    pub fn handle_input_shortcut(&mut self, key: &EventKey) -> bool {
        let keyval = key.get_keyval();
        let control_pressed = key.get_state() & CONTROL_MASK == CONTROL_MASK;
        if let Some(key) = gdk_key_to_key(keyval, control_pressed) {
            if self.shortcuts.contains_key(&key) {
                let answer = &self.shortcuts[&key].clone();
                self.set_dialog_answer(answer);
                self.shortcut_pressed = true;
                return true;
            }
        }
        false
    }
}*/
<commit_msg>Inhibit only shortcuts found in the config file<commit_after>/*
 * Copyright (c) 2016 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

use gdk::{EventKey, CONTROL_MASK, MOD1_MASK};
use gdk::enums::key::{Escape, Tab, ISO_Left_Tab};
use gtk::Inhibit;
use mg_settings::{self, EnumFromStr, EnumMetaData, SettingCompletion, SpecialCommand};
use mg_settings::key::Key;
use relm::Widget;

use app::{Mg, Msg, BLOCKING_INPUT_MODE, COMMAND_MODE, INPUT_MODE, NORMAL_MODE};
use app::ShortcutCommand::{Complete, Incomplete};
use key_converter::gdk_key_to_key;

/// Convert a shortcut of keys to a `String`.
pub fn shortcut_to_string(keys: &[Key]) -> String {
    let strings: Vec<_> = keys.iter().map(ToString::to_string).collect();
    strings.join("")
}

impl<COMM, SETT> Mg<COMM, SETT>
    where COMM: Clone + EnumFromStr + EnumMetaData + SpecialCommand + 'static,
          SETT: Default + EnumMetaData + mg_settings::settings::Settings + SettingCompletion + 'static,
{
    /// Add the key to the current shortcut.
    pub fn add_to_shortcut(&mut self, key: Key) {
        self.model.current_shortcut.push(key);
        self.update_shortcut_label();
    }

    /// Clear the current shortcut buffer.
    pub fn clear_shortcut(&mut self) {
        self.model.current_shortcut.clear();
        self.update_shortcut_label();
    }

    /// Handle a possible input of a shortcut.
    pub fn handle_shortcut(&mut self, key: &EventKey) -> (Option<Msg<COMM, SETT>>, Inhibit) {
        let keyval = key.get_keyval();
        let alt_pressed = key.get_state() & MOD1_MASK == MOD1_MASK;
        let control_pressed = key.get_state() & CONTROL_MASK == CONTROL_MASK;
        let mut should_inhibit = self.model.current_mode == NORMAL_MODE ||
            (self.model.current_mode == COMMAND_MODE && (keyval == Tab || keyval == ISO_Left_Tab)) ||
            self.inhibit_command_shortcut(key) || key.get_keyval() == Escape;
        if !self.model.entry_shown || alt_pressed || control_pressed || keyval == Tab || keyval == ISO_Left_Tab {
            if let Some(key) = gdk_key_to_key(key) {
                self.add_to_shortcut(key);
                let action = {
                    let mut current_mode = self.model.current_mode.clone();
                    // The input modes have the same mappings as the command mode.
                    if current_mode == INPUT_MODE || current_mode == BLOCKING_INPUT_MODE {
                        current_mode = COMMAND_MODE.to_string();
                    }
                    self.model.mappings.get(&current_mode.as_ref())
                        .and_then(|mappings| mappings.get(&self.model.current_shortcut).cloned())
                };
                if let Some(action) = action {
                    // FIXME: this is copied a couple of lines below.
                    if !self.model.entry_shown {
                        self.reset();
                    }
                    self.clear_shortcut();
                    match self.action_to_command(&action) {
                        Complete(command) => return (self.handle_command(Some(command)), Inhibit(should_inhibit)),
                        Incomplete(command) => {
                            self.input_command(&command);
                            //self.status_bar.show_completion();
                            //self.update_completions();
                            should_inhibit = true;
                        },
                    }
                }
                else if self.no_possible_shortcut() {
                    if !self.model.entry_shown {
                        self.reset();
                    }
                    self.clear_shortcut();
                }
            }
        }
        (None, Inhibit(should_inhibit))
    }

    /// Check if the current key is in the config file.
    fn inhibit_command_shortcut(&self, key: &EventKey) -> bool {
        if let Some(mappings) = self.model.mappings.get(COMMAND_MODE) {
            if let Some(typed_key) = gdk_key_to_key(key) {
                for keys in mappings.keys() {
                    for key in keys {
                        if *key == typed_key {
                            return true;
                        }
                    }
                }
            }
        }
        false
    }

    /// Check if there are no possible shortcuts.
    fn no_possible_shortcut(&self) -> bool {
        if let Some(mappings) = self.model.mappings.get(&self.model.current_mode.as_ref()) {
            for key in mappings.keys() {
                if key.starts_with(&self.model.current_shortcut) {
                    return false;
                }
            }
        }
        true
    }

    // TODO: remove this when updating the model in methods outside the trait will update the view.
    /// Update the shortcut label.
    fn update_shortcut_label(&self) {
        self.shortcut.widget().root().set_text(&shortcut_to_string(&self.model.current_shortcut));
    }
}

/*impl<Spec, Comm, Sett> Application<Comm, Sett, Spec>
    where Spec: SpecialCommand + 'static,
          Comm: EnumFromStr + EnumMetaData + 'static,
          Sett: mg_settings::settings::Settings + EnumMetaData + SettingCompletion + 'static,
{
    /// Handle a shortcut in input mode.
    pub fn handle_input_shortcut(&mut self, key: &EventKey) -> bool {
        let keyval = key.get_keyval();
        let control_pressed = key.get_state() & CONTROL_MASK == CONTROL_MASK;
        if let Some(key) = gdk_key_to_key(keyval, control_pressed) {
            if self.shortcuts.contains_key(&key) {
                let answer = &self.shortcuts[&key].clone();
                self.set_dialog_answer(answer);
                self.shortcut_pressed = true;
                return true;
            }
        }
        false
    }
}*/
<|endoftext|>


<commit_before>use std::str;
use std::convert;

use unicode_segmentation::UnicodeSegmentation;

#[cfg(test)]
mod test;

/// The index of a Unicode grapheme
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct GraphemeIndex(usize);

/// The index of a byte in a string
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct ByteIndex(usize);

/// The index of a Rust `char` in a string
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct CharIndex(usize);

impl GraphemeIndex {

    /// Returns the byte index in `text` corresponding to this grapheme index.
    ///
    /// # Arguments
    /// - `text`: the `&str` to find the byte index for this grapheme index in
    ///
    /// # Panics
    /// - If the index is to a grapheme that would lie outside of the length of
    ///   `text`.
    pub fn to_byte_index<'a>(&self, text: &'a str) -> ByteIndex {

        if text.grapheme_len() == self.0 {
            ByteIndex(text.len())
        } else {
            text.grapheme_indices(true)
                .find(|&(offset, _)| offset == self.0)
                .map( |(offset, _)| ByteIndex(offset))
                .expect(&format!( "grapheme index {} is greater than the length\
                                   of text {:?}"
                                 , self.0, text))
        }

    }

    /// Returns the Rust `char` index in `text` corresponding to this grapheme
    /// index.
    ///
    /// # Arguments
    /// - `text`: the `&str` to find the `char` index for this grapheme index in
    ///
    /// # Panics
    /// - If the index is to a grapheme that would lie outside of the length of
    ///   `text`.
    pub fn to_char_index<'a>(&self, text: &'a str) -> CharIndex  {

        text.graphemes(true)
            .scan(0usize, |char_count, grapheme| {
                    *char_count += grapheme.char_len();
                    Some(CharIndex(*char_count))
                })
            .nth(self.0)
            .expect(&format!( "grapheme index {} is greater than the length\
                               of text {:?}"
                             , self.0, text))
    }
}

impl CharIndex {
    fn to_byte_index<'a>(&self, into: &'a str) -> ByteIndex  {

        unimplemented!()
    }

    fn to_grapheme_index<'a>(&self, into: &'a str) -> GraphemeIndex {

        unimplemented!()
    }
}

// TODO: replace with impl Index<CharIndex> for str
impl convert::Into<usize> for CharIndex {
    #[inline] fn into(self) -> usize { self.0 }
}

impl convert::From<usize> for GraphemeIndex {
    #[inline] fn from(u: usize) -> Self { GraphemeIndex(u) }
}

impl ByteIndex {
    fn to_char_index<'a>(&self, into: &'a str) -> CharIndex {

        unimplemented!()
    }

    fn to_grapheme_index<'a>(&self, into: &'a str) -> GraphemeIndex  {

        unimplemented!()
    }
}

pub trait Unicode<'a> {
    // type GraphemeIndices: Iterator<Item = (usize, &'a str)>;
    // type CharIndices: Iterator<Item = (usize, char)>;
    // type ByteIndices: Iterator<Item = (usize, u8)>;
    //
    // fn grapheme_indices(&'a self) -> Self::GraphemeIndices;
    // fn char_indices(&'a self) -> Self::CharIndices;
    // fn byte_indices(&'a self) -> Self::ByteIndices;

    fn char_len(&self) -> usize;
    fn grapheme_len(&self) -> usize;
    fn byte_len(&self) -> usize;
}

impl<'a> Unicode<'a> for str {
    // type GraphemeIndices = USGraphemeIndices<'a>;
    // type CharIndices = str::CharIndices<'a>;
    // type ByteIndices = iter::Enumerate<str::Bytes<'a>>;
    //
    // #[inline]
    // fn grapheme_indices(&'a self) -> Self::GraphemeIndices {
    //     UnicodeSegmentation::grapheme_indices(self, true)
    // }
    //
    // #[inline]
    // fn char_indices(&'a self) -> Self::CharIndices { self.char_indices() }
    //
    // #[inline]
    // fn byte_indices(&'a self) -> Self::ByteIndices { self.bytes().enumerate() }

    #[inline]
    fn byte_len(&self) -> usize { self.len() }

    #[inline]
    fn char_len(&self) -> usize { self.chars().count() }

    #[inline]
    fn grapheme_len(&self) -> usize { self.graphemes(true).count() }
}
<commit_msg>style(unicode): remove elided lifetime parameters<commit_after>use std::str;
use std::convert;

use unicode_segmentation::UnicodeSegmentation;

#[cfg(test)]
mod test;

/// The index of a Unicode grapheme
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct GraphemeIndex(usize);

/// The index of a byte in a string
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct ByteIndex(usize);

/// The index of a Rust `char` in a string
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct CharIndex(usize);

impl GraphemeIndex {

    /// Returns the byte index in `text` corresponding to this grapheme index.
    ///
    /// # Arguments
    /// - `text`: the `&str` to find the byte index for this grapheme index in
    ///
    /// # Panics
    /// - If the index is to a grapheme that would lie outside of the length of
    ///   `text`.
    pub fn to_byte_index(&self, text: &str) -> ByteIndex {

        if text.grapheme_len() == self.0 {
            ByteIndex(text.len())
        } else {
            text.grapheme_indices(true)
                .find(|&(offset, _)| offset == self.0)
                .map( |(offset, _)| ByteIndex(offset))
                .expect(&format!( "grapheme index {} is greater than the length\
                                   of text {:?}"
                                 , self.0, text))
        }

    }

    /// Returns the Rust `char` index in `text` corresponding to this grapheme
    /// index.
    ///
    /// # Arguments
    /// - `text`: the `&str` to find the `char` index for this grapheme index in
    ///
    /// # Panics
    /// - If the index is to a grapheme that would lie outside of the length of
    ///   `text`.
    pub fn to_char_index(&self, text: &str) -> CharIndex  {

        text.graphemes(true)
            .scan(0usize, |char_count, grapheme| {
                    *char_count += grapheme.char_len();
                    Some(CharIndex(*char_count))
                })
            .nth(self.0)
            .expect(&format!( "grapheme index {} is greater than the length\
                               of text {:?}"
                             , self.0, text))
    }
}

impl CharIndex {
    fn to_byte_index(&self, into: &str) -> ByteIndex  {

        unimplemented!()
    }

    fn to_grapheme_index(&self, into: &str) -> GraphemeIndex {

        unimplemented!()
    }
}

// TODO: replace with impl Index<CharIndex> for str
impl convert::Into<usize> for CharIndex {
    #[inline] fn into(self) -> usize { self.0 }
}

impl convert::From<usize> for GraphemeIndex {
    #[inline] fn from(u: usize) -> Self { GraphemeIndex(u) }
}

impl ByteIndex {
    fn to_char_index(&self, into: &str) -> CharIndex {

        unimplemented!()
    }

    fn to_grapheme_index(&self, into: &str) -> GraphemeIndex  {

        unimplemented!()
    }
}

pub trait Unicode<'a> {
    // type GraphemeIndices: Iterator<Item = (usize, &'a str)>;
    // type CharIndices: Iterator<Item = (usize, char)>;
    // type ByteIndices: Iterator<Item = (usize, u8)>;
    //
    // fn grapheme_indices(&'a self) -> Self::GraphemeIndices;
    // fn char_indices(&'a self) -> Self::CharIndices;
    // fn byte_indices(&'a self) -> Self::ByteIndices;

    fn char_len(&self) -> usize;
    fn grapheme_len(&self) -> usize;
    fn byte_len(&self) -> usize;
}

impl<'a> Unicode<'a> for str {
    // type GraphemeIndices = USGraphemeIndices<'a>;
    // type CharIndices = str::CharIndices<'a>;
    // type ByteIndices = iter::Enumerate<str::Bytes<'a>>;
    //
    // #[inline]
    // fn grapheme_indices(&'a self) -> Self::GraphemeIndices {
    //     UnicodeSegmentation::grapheme_indices(self, true)
    // }
    //
    // #[inline]
    // fn char_indices(&'a self) -> Self::CharIndices { self.char_indices() }
    //
    // #[inline]
    // fn byte_indices(&'a self) -> Self::ByteIndices { self.bytes().enumerate() }

    #[inline]
    fn byte_len(&self) -> usize { self.len() }

    #[inline]
    fn char_len(&self) -> usize { self.chars().count() }

    #[inline]
    fn grapheme_len(&self) -> usize { self.graphemes(true).count() }
}
<|endoftext|>