<commit_before>use bridges::{BridgeData, complete_auth};
use config::GoogleConfig;
use crypto;
use email_address::EmailAddress;
use error::BrokerError;
use futures::{Future, future};
use http::{ContextHandle, HandlerResult};
use hyper::{Response, StatusCode};
use hyper::header::{ContentType, Location};
use serde_helpers::UrlDef;
use std::rc::Rc;
use store_cache::{CacheKey, fetch_json_url};
use time::now_utc;
use url::Url;
use url::percent_encoding::{utf8_percent_encode, QUERY_ENCODE_SET};
use validation;
use webfinger::{Link, Relation};

/// The origin of the Google identity provider.
pub const GOOGLE_IDP_ORIGIN: &str = "https://accounts.google.com";

/// Normalization to apply to an email address.
#[derive(Serialize,Deserialize)]
pub enum Normalization {
    None,
    Google,
}

impl Normalization {
    /// Apply normalization to an email address.
    pub fn apply(&self, email_addr: EmailAddress) -> EmailAddress {
        match *self {
            Normalization::None => email_addr,
            Normalization::Google => email_addr.normalize_google(),
        }
    }
}

/// Data we store in the session.
#[derive(Serialize,Deserialize)]
pub struct OidcBridgeData {
    pub origin: String,
    pub client_id: String,
    pub nonce: String,
    pub normalization: Normalization,
}

/// OpenID Connect configuration document.
#[derive(Deserialize)]
struct ProviderConfig {
    #[serde(with = "UrlDef")]
    authorization_endpoint: Url,
    #[serde(with = "UrlDef")]
    jwks_uri: Url,
}

/// OpenID Connect key set document.
#[derive(Deserialize)]
struct ProviderKeys {
    #[serde(default)]
    keys: Vec<ProviderKey>,
}

#[derive(Deserialize)]
pub struct ProviderKey {
    #[serde(default)]
    pub kid: String,
    #[serde(rename = "use")]
    #[serde(default)]
    pub use_: String,
    #[serde(default)]
    pub n: String,
    #[serde(default)]
    pub e: String,
}

/// Provide authentication using OpenID Connect.
///
/// Redirect the user agent to the provider authorization endpoint, which we discover by reading
/// the providers configuration document. Included in the request is a nonce which we can later use
/// to definitively match the callback to this request.
///
/// This function handles both Portier providers, which works without registration, as well as
/// the Google provider, for which we have a preregistered `client_id`.
pub fn auth(ctx_handle: &ContextHandle, email_addr: &Rc<EmailAddress>, link: &Link)
    -> HandlerResult {

    let ctx = ctx_handle.borrow();

    // Generate a nonce for the provider.
    let provider_nonce = crypto::nonce();

    // Determine the parameters to use, based on the webfinger link.
    let provider_origin = match validation::parse_oidc_href(&link.href) {
        Some(origin) => origin,
        None => return Box::new(future::err(BrokerError::Provider(
            format!("invalid href (validation failed): {}", link.href)))),
    };
    let bridge_data = Rc::new(match link.rel {
        Relation::Portier => {
            #[cfg(not(feature = "insecure"))] {
                if link.href.scheme() != "https" {
                    return Box::new(future::err(BrokerError::Provider(
                        format!("invalid href (not HTTPS): {}", link.href))));
                }
            }
            OidcBridgeData {
                origin: provider_origin,
                client_id: ctx.app.public_url.clone(),
                nonce: provider_nonce,
                normalization: Normalization::None,
            }
        },
        // Delegate to the OpenID Connect bridge for Google, if configured.
        Relation::Google => {
            let client_id = match ctx.app.google {
                Some(GoogleConfig { ref client_id }) => client_id,
                None => return Box::new(future::err(BrokerError::ProviderCancelled)),
            };
            if provider_origin != GOOGLE_IDP_ORIGIN {
                return Box::new(future::err(BrokerError::Provider(
                    format!("invalid href: Google provider only supports {}", GOOGLE_IDP_ORIGIN))));
            }
            OidcBridgeData {
                origin: provider_origin,
                client_id: client_id.clone(),
                nonce: provider_nonce,
                normalization: Normalization::Google,
            }
        },
    });

    // Retrieve the provider's configuration.
    let f = fetch_config(ctx_handle, &bridge_data);

    let ctx_handle = Rc::clone(ctx_handle);
    let email_addr = Rc::clone(email_addr);
    let f = f.and_then(move |provider_config: ProviderConfig| {
        let mut ctx = ctx_handle.borrow_mut();

        // Create the URL to redirect to, properly escaping all parameters.
        let result = Url::parse(&vec![
            provider_config.authorization_endpoint.as_str(),
            "?",
            "client_id=",
            &utf8_percent_encode(&bridge_data.client_id, QUERY_ENCODE_SET).to_string(),
            "&response_type=id_token",
            "&scope=",
            &utf8_percent_encode("openid email", QUERY_ENCODE_SET).to_string(),
            "&redirect_uri=",
            &utf8_percent_encode(&format!("{}/callback", &ctx.app.public_url),
                                 QUERY_ENCODE_SET).to_string(),
            "&state=",
            &utf8_percent_encode(&ctx.session_id, QUERY_ENCODE_SET).to_string(),
            "&nonce=",
            &utf8_percent_encode(&bridge_data.nonce, QUERY_ENCODE_SET).to_string(),
            "&login_hint=",
            &utf8_percent_encode(email_addr.as_str(), QUERY_ENCODE_SET).to_string(),
        ].join(""));
        let auth_url = result.map_err(|_| {
            let domain = email_addr.domain();
            BrokerError::Provider(
                format!("failed to build valid authorization URL from {}'s 'authorization_endpoint'", domain))
        })?;

        // Save session data, committing the session to this provider.
        let bridge_data = Rc::try_unwrap(bridge_data).map_err(|_| ()).expect("lingering oidc bridge data references");
        if !ctx.save_session(BridgeData::Oidc(bridge_data))? {
            return Err(BrokerError::ProviderCancelled);
        }

        let res = Response::new()
            .with_status(StatusCode::SeeOther)
            .with_header(Location::new(auth_url.into_string()));
        Ok(res)
    });

    Box::new(f)
}

/// Request handler for OpenID Connect callbacks with response mode 'fragment'
///
/// For providers that don't support `response_mode=form_post`, we capture the fragment parameters
/// in javascript and emulate the POST request.
pub fn fragment_callback(ctx_handle: &ContextHandle) -> HandlerResult {
    let ctx = ctx_handle.borrow();

    let res = Response::new()
        .with_header(ContentType::html())
        .with_body(ctx.app.templates.fragment_callback.render(&[]));
    Box::new(future::ok(res))
}

/// Request handler for OpenID Connect callbacks.
///
/// Match the returned email address and nonce against our session data, then extract the identity
/// token returned by the provider and verify it. Return an identity token for the relying party if
/// successful, or an error message otherwise.
pub fn callback(ctx_handle: &ContextHandle) -> HandlerResult {
    let (bridge_data, id_token) = {
        let mut ctx = ctx_handle.borrow_mut();
        let mut params = ctx.form_params();

        let session_id = try_get_provider_param!(params, "state");
        let bridge_data = match ctx.load_session(&session_id) {
            Ok(BridgeData::Oidc(bridge_data)) => Rc::new(bridge_data),
            Ok(_) => return Box::new(future::err(BrokerError::ProviderInput("invalid session".to_owned()))),
            Err(e) => return Box::new(future::err(e)),
        };

        let id_token = try_get_provider_param!(params, "id_token");
        (bridge_data, id_token)
    };

    // Retrieve the provider's configuration.
    let f = fetch_config(ctx_handle, &bridge_data);

    // Grab the keys from the provider, then verify the signature.
    let ctx_handle2 = Rc::clone(ctx_handle);
    let bridge_data2 = Rc::clone(&bridge_data);
    let f = f.and_then(move |provider_config: ProviderConfig| {
        let ctx = ctx_handle2.borrow();
        fetch_json_url(&ctx.app, provider_config.jwks_uri, &CacheKey::OidcKeySet {
            origin: bridge_data2.origin.as_str(),
        })
            .then(move |result| {
                let key_set: ProviderKeys = result.map_err(|e| BrokerError::Provider(
                    format!("could not fetch {}'s keys: {}", &bridge_data2.origin, e)))?;
                crypto::verify_jws(&id_token, &key_set.keys).map_err(|_| BrokerError::ProviderInput(
                    format!("could not verify the token received from {}", &bridge_data2.origin)))
            })
    });

    let ctx_handle = Rc::clone(ctx_handle);
    let f = f.and_then(move |jwt_payload| {
        let ctx = ctx_handle.borrow();
        let data = ctx.session_data.as_ref().expect("session vanished");

        // Normalize the email address according to provider rules.
        let email_addr = bridge_data.normalization.apply(data.email_addr.clone());

        // Extract the token claims.
        let descr = format!("{}'s token payload", email_addr.domain());
        let iss = try_get_token_field!(jwt_payload, "iss", descr);
        let aud = try_get_token_field!(jwt_payload, "aud", descr);
        let token_addr = try_get_token_field!(jwt_payload, "email", descr);
        let iat = try_get_token_field!(jwt_payload, "iat", |v| v.as_i64(), descr);
        let exp = try_get_token_field!(jwt_payload, "exp", |v| v.as_i64(), descr);
        let nonce = try_get_token_field!(jwt_payload, "nonce", descr);

        // Normalize the token email address too.
        let token_addr: EmailAddress = match token_addr.parse() {
            Ok(addr) => bridge_data.normalization.apply(addr),
            Err(_) => return Err(BrokerError::ProviderInput(format!(
                    "failed to parse email from {}", descr))),
        };

        // Verify the token claims.
        check_token_field!(iss == bridge_data.origin, "iss", descr);
        check_token_field!(aud == *bridge_data.client_id, "aud", descr);
        check_token_field!(nonce == *bridge_data.nonce, "nonce", descr);
        check_token_field!(token_addr == email_addr, "email", descr);

        let now = now_utc().to_timespec().sec;
        check_token_field!(now < exp, "exp", descr);
        check_token_field!(iat <= now, "iat", descr);

        // If everything is okay, build a new identity token and send it
        // to the relying party.
        complete_auth(&*ctx)
    });

    Box::new(f)
}

// Retrieve and verify the provider's configuration.
fn fetch_config(ctx_handle: &ContextHandle, bridge_data: &Rc<OidcBridgeData>)
    -> Box<Future<Item=ProviderConfig, Error=BrokerError>> {

    let config_url = format!("{}/.well-known/openid-configuration", bridge_data.origin).parse()
        .expect("could not build the OpenID Connect configuration URL");

    let ctx = ctx_handle.borrow();
    let bridge_data = Rc::clone(bridge_data);
    let f = fetch_json_url::<ProviderConfig>(&ctx.app, config_url, &CacheKey::OidcConfig {
        origin: bridge_data.origin.as_str(),
    });

    let f = f.then(move |result| {
        let provider_config = result.map_err(|e| BrokerError::Provider(
            format!("could not fetch {}'s configuration: {}", bridge_data.origin, e)))?;

        #[cfg(not(feature = "insecure"))] {
            if provider_config.authorization_endpoint.scheme() != "https" {
                return Err(BrokerError::Provider(
                    format!("{}'s authorization_endpoint is not HTTPS", bridge_data.origin)));
            }
            if provider_config.jwks_uri.scheme() != "https" {
                return Err(BrokerError::Provider(
                    format!("{}'s jwks_uri is not HTTPS", bridge_data.origin)));
            }
        }

        Ok(provider_config)
    });

    Box::new(f)
}
<commit_msg>Add leeway to iat & exp claims<commit_after>use bridges::{BridgeData, complete_auth};
use config::GoogleConfig;
use crypto;
use email_address::EmailAddress;
use error::BrokerError;
use futures::{Future, future};
use http::{ContextHandle, HandlerResult};
use hyper::{Response, StatusCode};
use hyper::header::{ContentType, Location};
use serde_helpers::UrlDef;
use std::rc::Rc;
use store_cache::{CacheKey, fetch_json_url};
use time::now_utc;
use url::Url;
use url::percent_encoding::{utf8_percent_encode, QUERY_ENCODE_SET};
use validation;
use webfinger::{Link, Relation};

/// The origin of the Google identity provider.
pub const GOOGLE_IDP_ORIGIN: &str = "https://accounts.google.com";
/// The leeway allowed when verifying iat & exp claims, in seconds.
pub const LEEWAY: i64 = 30;

/// Normalization to apply to an email address.
#[derive(Serialize,Deserialize)]
pub enum Normalization {
    None,
    Google,
}

impl Normalization {
    /// Apply normalization to an email address.
    pub fn apply(&self, email_addr: EmailAddress) -> EmailAddress {
        match *self {
            Normalization::None => email_addr,
            Normalization::Google => email_addr.normalize_google(),
        }
    }
}

/// Data we store in the session.
#[derive(Serialize,Deserialize)]
pub struct OidcBridgeData {
    pub origin: String,
    pub client_id: String,
    pub nonce: String,
    pub normalization: Normalization,
}

/// OpenID Connect configuration document.
#[derive(Deserialize)]
struct ProviderConfig {
    #[serde(with = "UrlDef")]
    authorization_endpoint: Url,
    #[serde(with = "UrlDef")]
    jwks_uri: Url,
}

/// OpenID Connect key set document.
#[derive(Deserialize)]
struct ProviderKeys {
    #[serde(default)]
    keys: Vec<ProviderKey>,
}

#[derive(Deserialize)]
pub struct ProviderKey {
    #[serde(default)]
    pub kid: String,
    #[serde(rename = "use")]
    #[serde(default)]
    pub use_: String,
    #[serde(default)]
    pub n: String,
    #[serde(default)]
    pub e: String,
}

/// Provide authentication using OpenID Connect.
///
/// Redirect the user agent to the provider authorization endpoint, which we discover by reading
/// the providers configuration document. Included in the request is a nonce which we can later use
/// to definitively match the callback to this request.
///
/// This function handles both Portier providers, which works without registration, as well as
/// the Google provider, for which we have a preregistered `client_id`.
pub fn auth(ctx_handle: &ContextHandle, email_addr: &Rc<EmailAddress>, link: &Link)
    -> HandlerResult {

    let ctx = ctx_handle.borrow();

    // Generate a nonce for the provider.
    let provider_nonce = crypto::nonce();

    // Determine the parameters to use, based on the webfinger link.
    let provider_origin = match validation::parse_oidc_href(&link.href) {
        Some(origin) => origin,
        None => return Box::new(future::err(BrokerError::Provider(
            format!("invalid href (validation failed): {}", link.href)))),
    };
    let bridge_data = Rc::new(match link.rel {
        Relation::Portier => {
            #[cfg(not(feature = "insecure"))] {
                if link.href.scheme() != "https" {
                    return Box::new(future::err(BrokerError::Provider(
                        format!("invalid href (not HTTPS): {}", link.href))));
                }
            }
            OidcBridgeData {
                origin: provider_origin,
                client_id: ctx.app.public_url.clone(),
                nonce: provider_nonce,
                normalization: Normalization::None,
            }
        },
        // Delegate to the OpenID Connect bridge for Google, if configured.
        Relation::Google => {
            let client_id = match ctx.app.google {
                Some(GoogleConfig { ref client_id }) => client_id,
                None => return Box::new(future::err(BrokerError::ProviderCancelled)),
            };
            if provider_origin != GOOGLE_IDP_ORIGIN {
                return Box::new(future::err(BrokerError::Provider(
                    format!("invalid href: Google provider only supports {}", GOOGLE_IDP_ORIGIN))));
            }
            OidcBridgeData {
                origin: provider_origin,
                client_id: client_id.clone(),
                nonce: provider_nonce,
                normalization: Normalization::Google,
            }
        },
    });

    // Retrieve the provider's configuration.
    let f = fetch_config(ctx_handle, &bridge_data);

    let ctx_handle = Rc::clone(ctx_handle);
    let email_addr = Rc::clone(email_addr);
    let f = f.and_then(move |provider_config: ProviderConfig| {
        let mut ctx = ctx_handle.borrow_mut();

        // Create the URL to redirect to, properly escaping all parameters.
        let result = Url::parse(&vec![
            provider_config.authorization_endpoint.as_str(),
            "?",
            "client_id=",
            &utf8_percent_encode(&bridge_data.client_id, QUERY_ENCODE_SET).to_string(),
            "&response_type=id_token",
            "&scope=",
            &utf8_percent_encode("openid email", QUERY_ENCODE_SET).to_string(),
            "&redirect_uri=",
            &utf8_percent_encode(&format!("{}/callback", &ctx.app.public_url),
                                 QUERY_ENCODE_SET).to_string(),
            "&state=",
            &utf8_percent_encode(&ctx.session_id, QUERY_ENCODE_SET).to_string(),
            "&nonce=",
            &utf8_percent_encode(&bridge_data.nonce, QUERY_ENCODE_SET).to_string(),
            "&login_hint=",
            &utf8_percent_encode(email_addr.as_str(), QUERY_ENCODE_SET).to_string(),
        ].join(""));
        let auth_url = result.map_err(|_| {
            let domain = email_addr.domain();
            BrokerError::Provider(
                format!("failed to build valid authorization URL from {}'s 'authorization_endpoint'", domain))
        })?;

        // Save session data, committing the session to this provider.
        let bridge_data = Rc::try_unwrap(bridge_data).map_err(|_| ()).expect("lingering oidc bridge data references");
        if !ctx.save_session(BridgeData::Oidc(bridge_data))? {
            return Err(BrokerError::ProviderCancelled);
        }

        let res = Response::new()
            .with_status(StatusCode::SeeOther)
            .with_header(Location::new(auth_url.into_string()));
        Ok(res)
    });

    Box::new(f)
}

/// Request handler for OpenID Connect callbacks with response mode 'fragment'
///
/// For providers that don't support `response_mode=form_post`, we capture the fragment parameters
/// in javascript and emulate the POST request.
pub fn fragment_callback(ctx_handle: &ContextHandle) -> HandlerResult {
    let ctx = ctx_handle.borrow();

    let res = Response::new()
        .with_header(ContentType::html())
        .with_body(ctx.app.templates.fragment_callback.render(&[]));
    Box::new(future::ok(res))
}

/// Request handler for OpenID Connect callbacks.
///
/// Match the returned email address and nonce against our session data, then extract the identity
/// token returned by the provider and verify it. Return an identity token for the relying party if
/// successful, or an error message otherwise.
pub fn callback(ctx_handle: &ContextHandle) -> HandlerResult {
    let (bridge_data, id_token) = {
        let mut ctx = ctx_handle.borrow_mut();
        let mut params = ctx.form_params();

        let session_id = try_get_provider_param!(params, "state");
        let bridge_data = match ctx.load_session(&session_id) {
            Ok(BridgeData::Oidc(bridge_data)) => Rc::new(bridge_data),
            Ok(_) => return Box::new(future::err(BrokerError::ProviderInput("invalid session".to_owned()))),
            Err(e) => return Box::new(future::err(e)),
        };

        let id_token = try_get_provider_param!(params, "id_token");
        (bridge_data, id_token)
    };

    // Retrieve the provider's configuration.
    let f = fetch_config(ctx_handle, &bridge_data);

    // Grab the keys from the provider, then verify the signature.
    let ctx_handle2 = Rc::clone(ctx_handle);
    let bridge_data2 = Rc::clone(&bridge_data);
    let f = f.and_then(move |provider_config: ProviderConfig| {
        let ctx = ctx_handle2.borrow();
        fetch_json_url(&ctx.app, provider_config.jwks_uri, &CacheKey::OidcKeySet {
            origin: bridge_data2.origin.as_str(),
        })
            .then(move |result| {
                let key_set: ProviderKeys = result.map_err(|e| BrokerError::Provider(
                    format!("could not fetch {}'s keys: {}", &bridge_data2.origin, e)))?;
                crypto::verify_jws(&id_token, &key_set.keys).map_err(|_| BrokerError::ProviderInput(
                    format!("could not verify the token received from {}", &bridge_data2.origin)))
            })
    });

    let ctx_handle = Rc::clone(ctx_handle);
    let f = f.and_then(move |jwt_payload| {
        let ctx = ctx_handle.borrow();
        let data = ctx.session_data.as_ref().expect("session vanished");

        // Normalize the email address according to provider rules.
        let email_addr = bridge_data.normalization.apply(data.email_addr.clone());

        // Extract the token claims.
        let descr = format!("{}'s token payload", email_addr.domain());
        let iss = try_get_token_field!(jwt_payload, "iss", descr);
        let aud = try_get_token_field!(jwt_payload, "aud", descr);
        let token_addr = try_get_token_field!(jwt_payload, "email", descr);
        let iat = try_get_token_field!(jwt_payload, "iat", |v| v.as_i64(), descr);
        let exp = try_get_token_field!(jwt_payload, "exp", |v| v.as_i64(), descr);
        let nonce = try_get_token_field!(jwt_payload, "nonce", descr);

        // Normalize the token email address too.
        let token_addr: EmailAddress = match token_addr.parse() {
            Ok(addr) => bridge_data.normalization.apply(addr),
            Err(_) => return Err(BrokerError::ProviderInput(format!(
                    "failed to parse email from {}", descr))),
        };

        // Verify the token claims.
        check_token_field!(iss == bridge_data.origin, "iss", descr);
        check_token_field!(aud == *bridge_data.client_id, "aud", descr);
        check_token_field!(nonce == *bridge_data.nonce, "nonce", descr);
        check_token_field!(token_addr == email_addr, "email", descr);

        let now = now_utc().to_timespec().sec;
        let exp = exp.checked_add(LEEWAY).unwrap_or(i64::min_value());
        let iat = iat.checked_sub(LEEWAY).unwrap_or(i64::max_value());
        check_token_field!(now < exp , "exp", descr);
        check_token_field!(iat <= now, "iat", descr);

        // If everything is okay, build a new identity token and send it
        // to the relying party.
        complete_auth(&*ctx)
    });

    Box::new(f)
}

// Retrieve and verify the provider's configuration.
fn fetch_config(ctx_handle: &ContextHandle, bridge_data: &Rc<OidcBridgeData>)
    -> Box<Future<Item=ProviderConfig, Error=BrokerError>> {

    let config_url = format!("{}/.well-known/openid-configuration", bridge_data.origin).parse()
        .expect("could not build the OpenID Connect configuration URL");

    let ctx = ctx_handle.borrow();
    let bridge_data = Rc::clone(bridge_data);
    let f = fetch_json_url::<ProviderConfig>(&ctx.app, config_url, &CacheKey::OidcConfig {
        origin: bridge_data.origin.as_str(),
    });

    let f = f.then(move |result| {
        let provider_config = result.map_err(|e| BrokerError::Provider(
            format!("could not fetch {}'s configuration: {}", bridge_data.origin, e)))?;

        #[cfg(not(feature = "insecure"))] {
            if provider_config.authorization_endpoint.scheme() != "https" {
                return Err(BrokerError::Provider(
                    format!("{}'s authorization_endpoint is not HTTPS", bridge_data.origin)));
            }
            if provider_config.jwks_uri.scheme() != "https" {
                return Err(BrokerError::Provider(
                    format!("{}'s jwks_uri is not HTTPS", bridge_data.origin)));
            }
        }

        Ok(provider_config)
    });

    Box::new(f)
}
<|endoftext|>


<commit_before>//!
//! A CAN database (dbc) format parser written with Rust's nom parser combinator library.
//! CAN databases are used to exchange details about a CAN network.
//! E.g. what messages are being send over the CAN bus and what data do they contain.
//!
//! ```rust
//! use can_dbc::DBC;
//! use codegen::Scope;
//!
//! use std::fs::File;
//! use std::io;
//! use std::io::prelude::*;
//!
//! fn main() -> io::Result<()> {
//!     let mut f = File::open("./examples/sample.dbc")?;
//!     let mut buffer = Vec::new();
//!     f.read_to_end(&mut buffer)?;
//!
//!     let dbc = can_dbc::DBC::from_slice(&buffer).expect("Failed to parse dbc file");
//!
//!     let mut scope = Scope::new();
//!     for message in dbc.messages() {
//!         for signal in message.signals() {
//!
//!             let mut scope = Scope::new();
//!             let message_struct = scope.new_struct(message.message_name());
//!             for signal in message.signals() {
//!                 message_struct.field(signal.name().to_lowercase().as_str(), "f64");
//!             }
//!         }
//!     }
//!
//!     println!("{}", scope.to_string());
//!     Ok(())
//! }
//! ```

use derive_getters::Getters;
use nom::*;
use nom::types::CompleteByteSlice;

pub mod parser;

#[cfg(test)]
mod tests {

    use super::*;
    use std::str;

    #[test]
    fn dbc_definition_test() {
        let sample_dbc =
        b"
VERSION \"0.1\"
NS_ :
    NS_DESC_
    CM_
    BA_DEF_
    BA_
    VAL_
    CAT_DEF_
    CAT_
    FILTER
    BA_DEF_DEF_
    EV_DATA_
    ENVVAR_DATA_
    SGTYPE_
    SGTYPE_VAL_
    BA_DEF_SGTYPE_
    BA_SGTYPE_
    SIG_TYPE_REF_
    VAL_TABLE_
    SIG_GROUP_
    SIG_VALTYPE_
    SIGTYPE_VALTYPE_
    BO_TX_BU_
    BA_DEF_REL_
    BA_REL_
    BA_DEF_DEF_REL_
    BU_SG_REL_
    BU_EV_REL_
    BU_BO_REL_
    SG_MUL_VAL_
BS_:
BU_: PC
BO_ 2000 WebData_2000: 4 Vector__XXX
    SG_ Signal_8 : 24|8@1+ (1,0) [0|255] \"\" Vector__XXX
    SG_ Signal_7 : 16|8@1+ (1,0) [0|255] \"\" Vector__XXX
    SG_ Signal_6 : 8|8@1+ (1,0) [0|255] \"\" Vector__XXX
    SG_ Signal_5 : 0|8@1+ (1,0) [0|255] \"\" Vector__XXX
BO_ 1840 WebData_1840: 4 PC
    SG_ Signal_4 : 24|8@1+ (1,0) [0|255] \"\" Vector__XXX
    SG_ Signal_3 : 16|8@1+ (1,0) [0|255] \"\" Vector__XXX
    SG_ Signal_2 : 8|8@1+ (1,0) [0|255] \"\" Vector__XXX
    SG_ Signal_1 : 0|8@1+ (1,0) [0|0] \"\" Vector__XXX

EV_ Environment1: 0 [0|220] \"\" 0 6 DUMMY_NODE_VECTOR0 DUMMY_NODE_VECTOR2;
EV_ Environment2: 0 [0|177] \"\" 0 7 DUMMY_NODE_VECTOR1 DUMMY_NODE_VECTOR2;
ENVVAR_DATA_ SomeEnvVarData: 399;

CM_ SG_ 4 TestSigLittleUnsigned1 \"asaklfjlsdfjlsdfgls
HH?=(%)/&KKDKFSDKFKDFKSDFKSDFNKCnvsdcvsvxkcv\";
CM_ SG_ 5 TestSigLittleUnsigned1 \"asaklfjlsdfjlsdfgls
=0943503450KFSDKFKDFKSDFKSDFNKCnvsdcvsvxkcv\";

BA_DEF_DEF_ \"BusType\" \"AS\";

BA_ \"Attr\" BO_ 4358435 283;
BA_ \"Attr\" BO_ 56949545 344;
";
        match DBC::from_slice(sample_dbc) {
            Ok(dbc_content) => println!("DBC Content{:#?}", dbc_content),
            Err(e) => {
                match e {
                    Error::NomError(nom::Err::Incomplete(needed)) => eprintln!("Error incomplete input, needed: {:?}", needed),
                    Error::NomError(nom::Err::Error(ctx)) => {
                        match ctx {
                            verbose_errors::Context::Code(i, kind) => eprintln!("Error Kind: {:?}, Code: {:?}", kind, str::from_utf8(i.as_bytes())),
                            verbose_errors::Context::List(l)=> eprintln!("Error List: {:?}", l),
                        }
                    }
                    Error::NomError(nom::Err::Failure(ctx)) => eprintln!("Failure {:?}", ctx),
                    Error::Incomplete(dbc, remaining) => eprintln!("Not all data in buffer was read {:#?}, remaining unparsed: {}", dbc, String::from_utf8(remaining).unwrap())
                }
                panic!("Failed to read DBC");
            }
        }
    }
}

/// Possible error cases for `can-dbc`
#[derive(Debug)]
pub enum Error<'a> {
    // Remaining String
    Incomplete(DBC, Vec<u8>),
    NomError(nom::Err<nom::types::CompleteByteSlice<'a>, u32>)
}

/// Baudrate of network in kbit/s
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Baudrate(u64);

/// One or multiple signals are the payload of a CAN frame.
/// To determine the actual value of a signal the following fn applies:
/// `let fnvalue = |can_signal_value| -> can_signal_value * factor + offset;`
#[derive(Clone, Debug, PartialEq, Getters)]
pub struct Signal {
    name: String,
    multiplexer_indicator: MultiplexIndicator,
    pub start_bit: u64,
    pub signal_size: u64,
    byte_order: ByteOrder,
    value_type: ValueType,
    pub factor: f64,
    pub offset: f64,
    pub min: f64,
    pub max: f64,
    unit: String,
    receivers: Vec<String>,
}

/// CAN id in header of CAN frame.
/// Must be unique in DBC file.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct MessageId(u64);

#[derive(Clone, Debug, PartialEq)]
pub enum Transmitter {
    /// node transmitting the message
    NodeName(String),
    /// message has no sender
    VectorXXX
}

#[derive(Clone, Debug, PartialEq, Getters)]
pub struct MessageTransmitter {
    message_id: MessageId,
    transmitter: Transmitter,
}

/// Version generated by DB editor
#[derive(Clone, Debug, PartialEq)]
pub struct Version(String);

#[derive(Clone, Debug, PartialEq)]
pub struct Symbol(String);

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum MultiplexIndicator {
    /// Multiplexor switch
    Multiplexor,
    /// Signal us being multiplexed by the multiplexer switch.
    MultiplexedSignal(u64),
    /// Normal signal
    Plain,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ByteOrder {
    LittleEndian,
    BigEndian,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ValueType {
    Signed,
    Unsigned,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum EnvType {
    EnvTypeFloat,
    EnvTypeu64,
    EnvTypeData,
}

#[derive(Clone, Debug, PartialEq, Getters)]
pub struct SignalType {
    signal_type_name: String,
    signal_size: u64,
    byte_order: ByteOrder,
    value_type: ValueType,
    factor: f64,
    offset: f64,
    min: f64,
    max: f64,
    unit: String,
    default_value: f64,
    value_table: String,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AccessType {
    DummyNodeVector0,
    DummyNodeVector1,
    DummyNodeVector2,
    DummyNodeVector3,
}

#[derive(Clone, Debug, PartialEq)]
pub enum AccessNode {
    AccessNodeVectorXXX,
    AccessNodeName(String),
}

#[derive(Clone, Debug, PartialEq)]
pub enum SignalAttributeValue {
    Text(String),
    Int(i64),
}

#[derive(Clone, Debug, PartialEq)]
pub enum AttributeValuedForObjectType {
    RawAttributeValue(AttributeValue),
    NetworkNodeAttributeValue(String, AttributeValue),
    MessageDefinitionAttributeValue(MessageId, Option<AttributeValue>),
    SignalAttributeValue(MessageId, String, AttributeValue),
    EnvVariableAttributeValue(String, AttributeValue),
}

#[derive(Clone, Debug, PartialEq)]
pub enum AttributeValueType {
    AttributeValueTypeInt(i64, i64),
    AttributeValueTypeHex(i64, i64),
    AttributeValueTypeFloat(f64, f64),
    AttributeValueTypeString,
    AttributeValueTypeEnum(Vec<String>),
}

#[derive(Clone, Debug, PartialEq, Getters)]
pub struct ValDescription {
    a: f64,
    b: String,
}

#[derive(Clone, Debug, PartialEq, Getters)]
pub struct AttrDefault {
    name: String,
    value: AttributeValue,
}

#[derive(Clone, Debug, PartialEq)]
pub enum AttributeValue {
    AttributeValueU64(u64),
    AttributeValueI64(i64),
    AttributeValueF64(f64),
    AttributeValueCharString(String),
}

/// Global value table
#[derive(Clone, Debug, PartialEq, Getters)]
pub struct ValueTable {
    value_table_name: String,
    value_descriptions: Vec<ValDescription>
}

/// Object comments
#[derive(Clone, Debug, PartialEq)]
pub enum Comment {
    Node { node_name: String, comment: String },
    Message { message_id: MessageId, comment: String },
    Signal { message_id: MessageId, signal_name: String, comment: String },
    EnvVar { env_var_name: String, comment: String },
    Plain { comment: String },
}

/// CAN message (frame) details including signal details
#[derive(Clone, Debug, PartialEq, Getters)]
pub struct Message {
    /// CAN id in header of CAN frame.
    /// Must be unique in DBC file.
    message_id: MessageId,
    message_name: String,
    message_size: u64,
    transmitter: Transmitter,
    signals: Vec<Signal>
}

#[derive(Clone, Debug, PartialEq, Getters)]
pub struct EnvironmentVariable {
    env_var_name: String,
    env_var_type: EnvType,
    min: i64,
    max: i64,
    unit: String,
    initial_value: f64,
    ev_id: i64,
    access_type: AccessType,
    access_nodes: Vec<AccessNode>,
}

#[derive(Clone, Debug, PartialEq, Getters)]
pub struct EnvironmentVariableData {
    env_var_name: String,
    data_size: u64,
}

/// CAN network nodes, names must be unique
#[derive(Clone, Debug, PartialEq)]
pub struct Node(Vec<String>);

#[derive(Clone,Debug, PartialEq, Getters)]
pub struct AttributeDefault {
    attribute_name: String,
    attribute_value: AttributeValue,
}

#[derive(Clone,Debug, PartialEq, Getters)]
pub struct AttributeValueForObject {
    attribute_name: String,
    attribute_value: AttributeValuedForObjectType,
}

#[derive(Clone, Debug, PartialEq)]
pub enum AttributeDefinition {
    // TODO add properties
    Message(String),
    // TODO add properties
    Node(String),
    // TODO add properties
    Signal(String),
    EnvironmentVariable(String),
    // TODO figure out name
    Plain(String),
}

/// Encoding for signal raw values.
#[derive(Clone, Debug, PartialEq)]
pub enum ValueDescription {
    Signal {
        message_id: MessageId,
        signal_name: String,
        value_descriptions: Vec<ValDescription>
    },
    EnvironmentVariable {
        env_var_name: String,
        value_descriptions: Vec<ValDescription>
    },
}

#[derive(Clone, Debug, PartialEq)]
pub struct SignalTypeRef {
    message_id: MessageId,
    signal_name: String,
    signal_type_name: String,
}

/// Signal groups define a group of signals within a message
#[derive(Clone, Debug, PartialEq)]
pub struct SignalGroups {
    message_id: MessageId,
    signal_group_name: String,
    repetitions: u64,
    signal_names: Vec<String>,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum SignalExtendedValueType {
    SignedOrUnsignedInteger,
    IEEEfloat32Bit,
    IEEEdouble64bit,
}

#[derive(Clone, Debug, PartialEq,Getters)]
pub struct SignalExtendedValueTypeList {
    message_id: MessageId,
    signal_name: String,
    signal_extended_value_type: SignalExtendedValueType
}

#[derive(Clone, Debug, PartialEq, Getters)]
pub struct DBC {
    /// Version generated by DB editor
    version: Version,
    new_symbols: Vec<Symbol>,
    /// Baud rate of network
    bit_timing: Option<Vec<Baudrate>>,
    /// CAN network nodes
    nodes: Vec<Node>,
    /// Global value table
    value_tables: Vec<ValueTable>,
    /// CAN message (frame) details including signal details
    messages: Vec<Message>,
    message_transmitters: Vec<MessageTransmitter>,
    environment_variables: Vec<EnvironmentVariable>,
    environment_variable_data: Vec<EnvironmentVariableData>,
    signal_types: Vec<SignalType>,
    /// Object comments
    comments: Vec<Comment>,
    attribute_definitions: Vec<AttributeDefinition>,
    // undefined
    // sigtype_attr_list: SigtypeAttrList,
    attribute_defaults: Vec<AttributeDefault>,
    attribute_values: Vec<AttributeValueForObject>,
    /// Encoding for signal raw values
    value_descriptions: Vec<ValueDescription>,
    // obsolete + undefined
    // category_definitions: Vec<CategoryDefinition>,
    // obsolete + undefined
    //categories: Vec<Category>,
    // obsolete + undefined
    //filter: Vec<Filter>,
    signal_type_refs: Vec<SignalTypeRef>,
    /// Signal groups define a group of signals within a message
    signal_groups: Option<SignalGroups>,
    signal_extended_value_type_list: Option<SignalExtendedValueTypeList>,
}

impl DBC {
    pub fn from_slice(buffer: &[u8]) -> Result<DBC, Error> {
        match parser::dbc(CompleteByteSlice(buffer)) {
            Ok((remaining, dbc)) => {
                if !remaining.is_empty() {
                    return Err(Error::Incomplete(dbc, remaining.as_bytes().to_vec()));
                }
                Ok(dbc)
            },
            Err(e) => Err(Error::NomError(e))
        }
    }
}<commit_msg>Derive missing getters<commit_after>//!
//! A CAN database (dbc) format parser written with Rust's nom parser combinator library.
//! CAN databases are used to exchange details about a CAN network.
//! E.g. what messages are being send over the CAN bus and what data do they contain.
//!
//! ```rust
//! use can_dbc::DBC;
//! use codegen::Scope;
//!
//! use std::fs::File;
//! use std::io;
//! use std::io::prelude::*;
//!
//! fn main() -> io::Result<()> {
//!     let mut f = File::open("./examples/sample.dbc")?;
//!     let mut buffer = Vec::new();
//!     f.read_to_end(&mut buffer)?;
//!
//!     let dbc = can_dbc::DBC::from_slice(&buffer).expect("Failed to parse dbc file");
//!
//!     let mut scope = Scope::new();
//!     for message in dbc.messages() {
//!         for signal in message.signals() {
//!
//!             let mut scope = Scope::new();
//!             let message_struct = scope.new_struct(message.message_name());
//!             for signal in message.signals() {
//!                 message_struct.field(signal.name().to_lowercase().as_str(), "f64");
//!             }
//!         }
//!     }
//!
//!     println!("{}", scope.to_string());
//!     Ok(())
//! }
//! ```

use derive_getters::Getters;
use nom::*;
use nom::types::CompleteByteSlice;

pub mod parser;

#[cfg(test)]
mod tests {

    use super::*;
    use std::str;

    #[test]
    fn dbc_definition_test() {
        let sample_dbc =
        b"
VERSION \"0.1\"
NS_ :
    NS_DESC_
    CM_
    BA_DEF_
    BA_
    VAL_
    CAT_DEF_
    CAT_
    FILTER
    BA_DEF_DEF_
    EV_DATA_
    ENVVAR_DATA_
    SGTYPE_
    SGTYPE_VAL_
    BA_DEF_SGTYPE_
    BA_SGTYPE_
    SIG_TYPE_REF_
    VAL_TABLE_
    SIG_GROUP_
    SIG_VALTYPE_
    SIGTYPE_VALTYPE_
    BO_TX_BU_
    BA_DEF_REL_
    BA_REL_
    BA_DEF_DEF_REL_
    BU_SG_REL_
    BU_EV_REL_
    BU_BO_REL_
    SG_MUL_VAL_
BS_:
BU_: PC
BO_ 2000 WebData_2000: 4 Vector__XXX
    SG_ Signal_8 : 24|8@1+ (1,0) [0|255] \"\" Vector__XXX
    SG_ Signal_7 : 16|8@1+ (1,0) [0|255] \"\" Vector__XXX
    SG_ Signal_6 : 8|8@1+ (1,0) [0|255] \"\" Vector__XXX
    SG_ Signal_5 : 0|8@1+ (1,0) [0|255] \"\" Vector__XXX
BO_ 1840 WebData_1840: 4 PC
    SG_ Signal_4 : 24|8@1+ (1,0) [0|255] \"\" Vector__XXX
    SG_ Signal_3 : 16|8@1+ (1,0) [0|255] \"\" Vector__XXX
    SG_ Signal_2 : 8|8@1+ (1,0) [0|255] \"\" Vector__XXX
    SG_ Signal_1 : 0|8@1+ (1,0) [0|0] \"\" Vector__XXX

EV_ Environment1: 0 [0|220] \"\" 0 6 DUMMY_NODE_VECTOR0 DUMMY_NODE_VECTOR2;
EV_ Environment2: 0 [0|177] \"\" 0 7 DUMMY_NODE_VECTOR1 DUMMY_NODE_VECTOR2;
ENVVAR_DATA_ SomeEnvVarData: 399;

CM_ SG_ 4 TestSigLittleUnsigned1 \"asaklfjlsdfjlsdfgls
HH?=(%)/&KKDKFSDKFKDFKSDFKSDFNKCnvsdcvsvxkcv\";
CM_ SG_ 5 TestSigLittleUnsigned1 \"asaklfjlsdfjlsdfgls
=0943503450KFSDKFKDFKSDFKSDFNKCnvsdcvsvxkcv\";

BA_DEF_DEF_ \"BusType\" \"AS\";

BA_ \"Attr\" BO_ 4358435 283;
BA_ \"Attr\" BO_ 56949545 344;
";
        match DBC::from_slice(sample_dbc) {
            Ok(dbc_content) => println!("DBC Content{:#?}", dbc_content),
            Err(e) => {
                match e {
                    Error::NomError(nom::Err::Incomplete(needed)) => eprintln!("Error incomplete input, needed: {:?}", needed),
                    Error::NomError(nom::Err::Error(ctx)) => {
                        match ctx {
                            verbose_errors::Context::Code(i, kind) => eprintln!("Error Kind: {:?}, Code: {:?}", kind, str::from_utf8(i.as_bytes())),
                            verbose_errors::Context::List(l)=> eprintln!("Error List: {:?}", l),
                        }
                    }
                    Error::NomError(nom::Err::Failure(ctx)) => eprintln!("Failure {:?}", ctx),
                    Error::Incomplete(dbc, remaining) => eprintln!("Not all data in buffer was read {:#?}, remaining unparsed: {}", dbc, String::from_utf8(remaining).unwrap())
                }
                panic!("Failed to read DBC");
            }
        }
    }
}

/// Possible error cases for `can-dbc`
#[derive(Debug)]
pub enum Error<'a> {
    // Remaining String
    Incomplete(DBC, Vec<u8>),
    NomError(nom::Err<nom::types::CompleteByteSlice<'a>, u32>)
}

/// Baudrate of network in kbit/s
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Baudrate(u64);

/// One or multiple signals are the payload of a CAN frame.
/// To determine the actual value of a signal the following fn applies:
/// `let fnvalue = |can_signal_value| -> can_signal_value * factor + offset;`
#[derive(Clone, Debug, PartialEq, Getters)]
pub struct Signal {
    name: String,
    multiplexer_indicator: MultiplexIndicator,
    pub start_bit: u64,
    pub signal_size: u64,
    byte_order: ByteOrder,
    value_type: ValueType,
    pub factor: f64,
    pub offset: f64,
    pub min: f64,
    pub max: f64,
    unit: String,
    receivers: Vec<String>,
}

/// CAN id in header of CAN frame.
/// Must be unique in DBC file.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct MessageId(u64);

#[derive(Clone, Debug, PartialEq)]
pub enum Transmitter {
    /// node transmitting the message
    NodeName(String),
    /// message has no sender
    VectorXXX
}

#[derive(Clone, Debug, PartialEq, Getters)]
pub struct MessageTransmitter {
    message_id: MessageId,
    transmitter: Transmitter,
}

/// Version generated by DB editor
#[derive(Clone, Debug, PartialEq)]
pub struct Version(String);

#[derive(Clone, Debug, PartialEq)]
pub struct Symbol(String);

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum MultiplexIndicator {
    /// Multiplexor switch
    Multiplexor,
    /// Signal us being multiplexed by the multiplexer switch.
    MultiplexedSignal(u64),
    /// Normal signal
    Plain,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ByteOrder {
    LittleEndian,
    BigEndian,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ValueType {
    Signed,
    Unsigned,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum EnvType {
    EnvTypeFloat,
    EnvTypeu64,
    EnvTypeData,
}

#[derive(Clone, Debug, PartialEq, Getters)]
pub struct SignalType {
    signal_type_name: String,
    signal_size: u64,
    byte_order: ByteOrder,
    value_type: ValueType,
    factor: f64,
    offset: f64,
    min: f64,
    max: f64,
    unit: String,
    default_value: f64,
    value_table: String,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AccessType {
    DummyNodeVector0,
    DummyNodeVector1,
    DummyNodeVector2,
    DummyNodeVector3,
}

#[derive(Clone, Debug, PartialEq)]
pub enum AccessNode {
    AccessNodeVectorXXX,
    AccessNodeName(String),
}

#[derive(Clone, Debug, PartialEq)]
pub enum SignalAttributeValue {
    Text(String),
    Int(i64),
}

#[derive(Clone, Debug, PartialEq)]
pub enum AttributeValuedForObjectType {
    RawAttributeValue(AttributeValue),
    NetworkNodeAttributeValue(String, AttributeValue),
    MessageDefinitionAttributeValue(MessageId, Option<AttributeValue>),
    SignalAttributeValue(MessageId, String, AttributeValue),
    EnvVariableAttributeValue(String, AttributeValue),
}

#[derive(Clone, Debug, PartialEq)]
pub enum AttributeValueType {
    AttributeValueTypeInt(i64, i64),
    AttributeValueTypeHex(i64, i64),
    AttributeValueTypeFloat(f64, f64),
    AttributeValueTypeString,
    AttributeValueTypeEnum(Vec<String>),
}

#[derive(Clone, Debug, PartialEq, Getters)]
pub struct ValDescription {
    a: f64,
    b: String,
}

#[derive(Clone, Debug, PartialEq, Getters)]
pub struct AttrDefault {
    name: String,
    value: AttributeValue,
}

#[derive(Clone, Debug, PartialEq)]
pub enum AttributeValue {
    AttributeValueU64(u64),
    AttributeValueI64(i64),
    AttributeValueF64(f64),
    AttributeValueCharString(String),
}

/// Global value table
#[derive(Clone, Debug, PartialEq, Getters)]
pub struct ValueTable {
    value_table_name: String,
    value_descriptions: Vec<ValDescription>
}

/// Object comments
#[derive(Clone, Debug, PartialEq)]
pub enum Comment {
    Node { node_name: String, comment: String },
    Message { message_id: MessageId, comment: String },
    Signal { message_id: MessageId, signal_name: String, comment: String },
    EnvVar { env_var_name: String, comment: String },
    Plain { comment: String },
}

/// CAN message (frame) details including signal details
#[derive(Clone, Debug, PartialEq, Getters)]
pub struct Message {
    /// CAN id in header of CAN frame.
    /// Must be unique in DBC file.
    message_id: MessageId,
    message_name: String,
    message_size: u64,
    transmitter: Transmitter,
    signals: Vec<Signal>
}

#[derive(Clone, Debug, PartialEq, Getters)]
pub struct EnvironmentVariable {
    env_var_name: String,
    env_var_type: EnvType,
    min: i64,
    max: i64,
    unit: String,
    initial_value: f64,
    ev_id: i64,
    access_type: AccessType,
    access_nodes: Vec<AccessNode>,
}

#[derive(Clone, Debug, PartialEq, Getters)]
pub struct EnvironmentVariableData {
    env_var_name: String,
    data_size: u64,
}

/// CAN network nodes, names must be unique
#[derive(Clone, Debug, PartialEq)]
pub struct Node(Vec<String>);

#[derive(Clone,Debug, PartialEq, Getters)]
pub struct AttributeDefault {
    attribute_name: String,
    attribute_value: AttributeValue,
}

#[derive(Clone,Debug, PartialEq, Getters)]
pub struct AttributeValueForObject {
    attribute_name: String,
    attribute_value: AttributeValuedForObjectType,
}

#[derive(Clone, Debug, PartialEq)]
pub enum AttributeDefinition {
    // TODO add properties
    Message(String),
    // TODO add properties
    Node(String),
    // TODO add properties
    Signal(String),
    EnvironmentVariable(String),
    // TODO figure out name
    Plain(String),
}

/// Encoding for signal raw values.
#[derive(Clone, Debug, PartialEq)]
pub enum ValueDescription {
    Signal {
        message_id: MessageId,
        signal_name: String,
        value_descriptions: Vec<ValDescription>
    },
    EnvironmentVariable {
        env_var_name: String,
        value_descriptions: Vec<ValDescription>
    },
}

#[derive(Clone, Debug, PartialEq, Getters)]
pub struct SignalTypeRef {
    message_id: MessageId,
    signal_name: String,
    signal_type_name: String,
}

/// Signal groups define a group of signals within a message
#[derive(Clone, Debug, PartialEq, Getters)]
pub struct SignalGroups {
    message_id: MessageId,
    signal_group_name: String,
    repetitions: u64,
    signal_names: Vec<String>,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum SignalExtendedValueType {
    SignedOrUnsignedInteger,
    IEEEfloat32Bit,
    IEEEdouble64bit,
}

#[derive(Clone, Debug, PartialEq, Getters)]
pub struct SignalExtendedValueTypeList {
    message_id: MessageId,
    signal_name: String,
    signal_extended_value_type: SignalExtendedValueType
}

#[derive(Clone, Debug, PartialEq, Getters)]
pub struct DBC {
    /// Version generated by DB editor
    version: Version,
    new_symbols: Vec<Symbol>,
    /// Baud rate of network
    bit_timing: Option<Vec<Baudrate>>,
    /// CAN network nodes
    nodes: Vec<Node>,
    /// Global value table
    value_tables: Vec<ValueTable>,
    /// CAN message (frame) details including signal details
    messages: Vec<Message>,
    message_transmitters: Vec<MessageTransmitter>,
    environment_variables: Vec<EnvironmentVariable>,
    environment_variable_data: Vec<EnvironmentVariableData>,
    signal_types: Vec<SignalType>,
    /// Object comments
    comments: Vec<Comment>,
    attribute_definitions: Vec<AttributeDefinition>,
    // undefined
    // sigtype_attr_list: SigtypeAttrList,
    attribute_defaults: Vec<AttributeDefault>,
    attribute_values: Vec<AttributeValueForObject>,
    /// Encoding for signal raw values
    value_descriptions: Vec<ValueDescription>,
    // obsolete + undefined
    // category_definitions: Vec<CategoryDefinition>,
    // obsolete + undefined
    //categories: Vec<Category>,
    // obsolete + undefined
    //filter: Vec<Filter>,
    signal_type_refs: Vec<SignalTypeRef>,
    /// Signal groups define a group of signals within a message
    signal_groups: Option<SignalGroups>,
    signal_extended_value_type_list: Option<SignalExtendedValueTypeList>,
}

impl DBC {
    pub fn from_slice(buffer: &[u8]) -> Result<DBC, Error> {
        match parser::dbc(CompleteByteSlice(buffer)) {
            Ok((remaining, dbc)) => {
                if !remaining.is_empty() {
                    return Err(Error::Incomplete(dbc, remaining.as_bytes().to_vec()));
                }
                Ok(dbc)
            },
            Err(e) => Err(Error::NomError(e))
        }
    }
}<|endoftext|>


<commit_before>
use color::Color;
use graphics::math::Scalar;
use position::{self, Dimensions, Direction, Point};
use theme::Theme;
use ui::{self, Ui};

use super::{CanvasId, Kind};

/// The length of a Split.
pub type Length = Scalar;

/// The current state of a Split.
#[derive(Clone, Debug, PartialEq)]
pub struct State;

/// A type of Canvas for flexibly designing and guiding widget layout as splits of a window.
pub struct Split<'a> {
    id: CanvasId,
    maybe_splits: Option<(Direction, &'a [Split<'a>])>,
    maybe_length: Option<f64>,
    style: Style,
    //maybe_adjustable: Option<Bounds>,
}

/// Describes the style of a Canvas Split.
#[derive(Clone, Debug, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Style {
    maybe_frame: Option<f64>,
    maybe_frame_color: Option<Color>,
    maybe_color: Option<Color>,
    padding: Padding,
    margin: Margin,
}

/// The distance between the edge of a widget and the inner edge of a Canvas' frame.
#[derive(Clone, Debug, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Padding {
    maybe_top: Option<f64>,
    maybe_bottom: Option<f64>,
    maybe_left: Option<f64>,
    maybe_right: Option<f64>,
}

/// The distance between the edge of a Canvas' outer dimensions and the outer edge of its frame.
#[derive(Clone, Debug, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Margin {
    maybe_top: Option<f64>,
    maybe_bottom: Option<f64>,
    maybe_left: Option<f64>,
    maybe_right: Option<f64>,
}

impl<'a> Split<'a> {

    /// Construct a default Canvas Split.
    pub fn new(id: CanvasId) -> Split<'a> {
        Split {
            id: id,
            maybe_splits: None,
            maybe_length: None,
            //maybe_adjustable: None,
            style: Style::new(),
        }
    }

    /// Set the dimension of the Split.
    pub fn length(mut self, length: Length) -> Split<'a> {
        self.maybe_length = Some(length);
        self
    }

    /// Set the child Canvas Splits of the current Canvas flowing in a given direction.
    pub fn flow(mut self, dir: Direction, splits: &'a [Split<'a>]) -> Split<'a> {
        self.maybe_splits = Some((dir, splits));
        self
    }

    /// Set the child Canvasses flowing downwards.
    pub fn flow_down(self, splits: &'a [Split<'a>]) -> Split<'a> {
        self.flow(Direction::Down, splits)
    }

    /// Set the child Canvasses flowing upwards.
    pub fn flow_up(self, splits: &'a [Split<'a>]) -> Split<'a> {
        self.flow(Direction::Up, splits)
    }

    /// Set the child Canvasses flowing to the right.
    pub fn flow_right(self, splits: &'a [Split<'a>]) -> Split<'a> {
        self.flow(Direction::Right, splits)
    }

    /// Set the child Canvasses flowing to the left.
    pub fn flow_left(self, splits: &'a [Split<'a>]) -> Split<'a> {
        self.flow(Direction::Left, splits)
    }

    /// Set the padding from the left edge.
    pub fn pad_left(mut self, pad: Scalar) -> Split<'a> {
        self.style.padding.maybe_left = Some(pad);
        self
    }

    /// Set the padding from the right edge.
    pub fn pad_right(mut self, pad: Scalar) -> Split<'a> {
        self.style.padding.maybe_right = Some(pad);
        self
    }

    /// Set the padding from the top edge.
    pub fn pad_top(mut self, pad: Scalar) -> Split<'a> {
        self.style.padding.maybe_top = Some(pad);
        self
    }

    /// Set the padding from the bottom edge.
    pub fn pad_bottom(mut self, pad: Scalar) -> Split<'a> {
        self.style.padding.maybe_bottom = Some(pad);
        self
    }

    /// Set the padding for all edges.
    pub fn pad(self, pad: Scalar) -> Split<'a> {
        self.pad_left(pad).pad_right(pad).pad_top(pad).pad_bottom(pad)
    }

    /// Set the margin from the left edge.
    pub fn margin_left(mut self, pad: Scalar) -> Split<'a> {
        self.style.margin.maybe_left = Some(pad);
        self
    }

    /// Set the margin from the right edge.
    pub fn margin_right(mut self, pad: Scalar) -> Split<'a> {
        self.style.margin.maybe_right = Some(pad);
        self
    }

    /// Set the margin from the top edge.
    pub fn margin_top(mut self, pad: Scalar) -> Split<'a> {
        self.style.margin.maybe_top = Some(pad);
        self
    }

    /// Set the margin from the bottom edge.
    pub fn margin_bottom(mut self, pad: Scalar) -> Split<'a> {
        self.style.margin.maybe_bottom = Some(pad);
        self
    }

    /// Set the margin for all edges.
    pub fn margin(self, pad: Scalar) -> Split<'a> {
        self.margin_left(pad).margin_right(pad).margin_top(pad).margin_bottom(pad)
    }

    /// Store the Canvas and it's children within the `Ui`. Each Canvas can be accessed via it's
    /// unique identifier `CanvasId`.
    pub fn set<C>(self, ui: &mut Ui<C>) {
        let dim = [ui.win_w as f64, ui.win_h as f64];
        self.into_ui(dim, [0.0, 0.0], ui);
    }

    /// Construct a Canvas from a Split.
    fn into_ui<C>(&self, dim: Dimensions, xy: Point, ui: &mut Ui<C>) {
        use elmesque::form::{rect, collage};
        use vecmath::{vec2_add, vec2_sub, vec2_scale};
        let Split { id, ref maybe_splits, ref style, .. } = *self;

        let color = style.color(&ui.theme);
        let frame_color = style.frame_color(&ui.theme);
        let frame = style.frame(&ui.theme);
        let pad = style.padding(&ui.theme);
        let mgn = style.margin(&ui.theme);

        let mgn_offset = [(mgn.left - mgn.right), (mgn.bottom - mgn.top)];
        let dim = vec2_sub(dim, [mgn.left + mgn.right, mgn.top + mgn.bottom]);
        let frame_dim = vec2_sub(dim, [frame * 2.0; 2]);
        let pad_offset = [(pad.bottom - pad.top), (pad.left - pad.right)];
        let pad_dim = vec2_sub(frame_dim, [pad.left + pad.right, pad.top + pad.bottom]);

        // Offset xy so that it is in the center of the given margin.
        let xy = vec2_add(xy, mgn_offset);

        if let Some((direction, splits)) = *maybe_splits {
            use position::{align_top_of, align_bottom_of, align_left_of, align_right_of};
            // Offset xy so that it is in the center of the padded area.
            let xy = vec2_add(xy, pad_offset);
            let num = splits.len() as f64;
            let split_dim = match splits.len() {
                0 => [0.0, 0.0],
                1 => pad_dim,
                _ => match direction {
                    Direction::Up   | Direction::Down  => [pad_dim[0], pad_dim[1] / num],
                    Direction::Left | Direction::Right => [pad_dim[0] / num, pad_dim[1]],
                },
            };
            let split_offset = match direction {
                Direction::Up    => [0.0, split_dim[1]],
                Direction::Down  => [0.0, -split_dim[1]],
                Direction::Left  => [-split_dim[0], 0.0],
                Direction::Right => [split_dim[0], 0.0],
            };
            let first_xy = match direction {
                Direction::Up    => [xy[0], xy[1] + align_bottom_of(pad_dim[1], split_dim[1])],
                Direction::Down  => [xy[0], xy[1] + align_top_of(pad_dim[1], split_dim[1])],
                Direction::Left  => [xy[0] + align_right_of(pad_dim[0], split_dim[0]), xy[1]],
                Direction::Right => [xy[0] + align_left_of(pad_dim[0], split_dim[0]), xy[1]],
            };

            for (i, split) in splits.iter().enumerate() {
                let split_xy = vec2_add(first_xy, vec2_scale(split_offset, i as f64));
                split.into_ui(split_dim, split_xy, ui)
            }
        }

        let frame_form = rect(dim[0], dim[1]).filled(frame_color);
        let inner_form = rect(frame_dim[0], frame_dim[1]).filled(color);
        let form_chain = Some(frame_form).into_iter()
            .chain(Some(inner_form).into_iter())
            .map(|form| form.shift(xy[0], xy[1]));

        let element = collage(frame_dim[0] as i32, frame_dim[1] as i32, form_chain.collect());

        let widget_area_xy = xy;
        let widget_area_dim = dim;

        ui::update_canvas(ui, id, Kind::Split(State), xy, widget_area_xy,
                          widget_area_dim, pad, Some(element));
    }

}

impl Style {

    /// Construct a default Style.
    pub fn new() -> Style {
        Style {
            maybe_frame: None,
            maybe_frame_color: None,
            maybe_color: None,
            padding: Padding::new(),
            margin: Margin::new(),
        }
    }

    /// Get the color for the Split's Element.
    pub fn color(&self, theme: &Theme) -> Color {
        self.maybe_color.or(theme.maybe_canvas_split.as_ref().map(|style| {
            style.maybe_color.unwrap_or(theme.background_color)
        })).unwrap_or(theme.background_color)
    }

    /// Get the frame for an Element.
    pub fn frame(&self, theme: &Theme) -> f64 {
        self.maybe_frame.or(theme.maybe_canvas_split.as_ref().map(|style| {
            style.maybe_frame.unwrap_or(theme.frame_width)
        })).unwrap_or(theme.frame_width)
    }

    /// Get the frame Color for an Element.
    pub fn frame_color(&self, theme: &Theme) -> Color {
        self.maybe_frame_color.or(theme.maybe_canvas_split.as_ref().map(|style| {
            style.maybe_frame_color.unwrap_or(theme.frame_color)
        })).unwrap_or(theme.frame_color)
    }

    /// Get the Padding for the Canvas Split.
    pub fn padding(&self, theme: &Theme) -> position::Padding {
        position::Padding {
            top: self.padding.maybe_top.or(theme.maybe_canvas_split.as_ref().map(|style| {
                style.padding.maybe_top.unwrap_or(theme.padding.top)
            })).unwrap_or(theme.padding.top),
            bottom: self.padding.maybe_bottom.or(theme.maybe_canvas_split.as_ref().map(|style| {
                style.padding.maybe_bottom.unwrap_or(theme.padding.bottom)
            })).unwrap_or(theme.padding.bottom),
            left: self.padding.maybe_left.or(theme.maybe_canvas_split.as_ref().map(|style| {
                style.padding.maybe_left.unwrap_or(theme.padding.left)
            })).unwrap_or(theme.padding.left),
            right: self.padding.maybe_right.or(theme.maybe_canvas_split.as_ref().map(|style| {
                style.padding.maybe_right.unwrap_or(theme.padding.right)
            })).unwrap_or(theme.padding.right),
        }
    }

    /// Get the Margin for the Canvas Split.
    pub fn margin(&self, theme: &Theme) -> position::Margin {
        position::Margin {
            top: self.margin.maybe_top.or(theme.maybe_canvas_split.as_ref().map(|style| {
                style.margin.maybe_top.unwrap_or(theme.margin.top)
            })).unwrap_or(theme.margin.top),
            bottom: self.margin.maybe_bottom.or(theme.maybe_canvas_split.as_ref().map(|style| {
                style.margin.maybe_bottom.unwrap_or(theme.margin.bottom)
            })).unwrap_or(theme.margin.bottom),
            left: self.margin.maybe_left.or(theme.maybe_canvas_split.as_ref().map(|style| {
                style.margin.maybe_left.unwrap_or(theme.margin.left)
            })).unwrap_or(theme.margin.left),
            right: self.margin.maybe_right.or(theme.maybe_canvas_split.as_ref().map(|style| {
                style.margin.maybe_right.unwrap_or(theme.margin.right)
            })).unwrap_or(theme.margin.right),
        }
    }

}

impl Padding {
    /// Construct a defualt Padding.
    pub fn new() -> Padding {
        Padding {
            maybe_top: None,
            maybe_bottom: None,
            maybe_left: None,
            maybe_right: None,
        }
    }
}

impl Margin {
    /// Construct a defualt Margin.
    pub fn new() -> Margin {
        Margin {
            maybe_top: None,
            maybe_bottom: None,
            maybe_left: None,
            maybe_right: None,
        }
    }
}

impl<'a> ::color::Colorable for Split<'a> {
    fn color(mut self, color: Color) -> Self {
        self.style.maybe_color = Some(color);
        self
    }
}

impl<'a> ::frame::Frameable for Split<'a> {
    fn frame(mut self, width: f64) -> Self {
        self.style.maybe_frame = Some(width);
        self
    }
    fn frame_color(mut self, color: Color) -> Self {
        self.style.maybe_frame_color = Some(color);
        self
    }
}

<commit_msg>Added support for .length() in Split.<commit_after>
use color::Color;
use graphics::math::Scalar;
use position::{self, Dimensions, Direction, Point};
use theme::Theme;
use ui::{self, Ui};

use super::{CanvasId, Kind};

/// The length of a Split.
pub type Length = Scalar;

/// The current state of a Split.
#[derive(Clone, Debug, PartialEq)]
pub struct State;

/// A type of Canvas for flexibly designing and guiding widget layout as splits of a window.
pub struct Split<'a> {
    id: CanvasId,
    maybe_splits: Option<(Direction, &'a [Split<'a>])>,
    maybe_length: Option<f64>,
    style: Style,
    //maybe_adjustable: Option<Bounds>,
}

/// Describes the style of a Canvas Split.
#[derive(Clone, Debug, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Style {
    maybe_frame: Option<f64>,
    maybe_frame_color: Option<Color>,
    maybe_color: Option<Color>,
    padding: Padding,
    margin: Margin,
}

/// The distance between the edge of a widget and the inner edge of a Canvas' frame.
#[derive(Clone, Debug, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Padding {
    maybe_top: Option<f64>,
    maybe_bottom: Option<f64>,
    maybe_left: Option<f64>,
    maybe_right: Option<f64>,
}

/// The distance between the edge of a Canvas' outer dimensions and the outer edge of its frame.
#[derive(Clone, Debug, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Margin {
    maybe_top: Option<f64>,
    maybe_bottom: Option<f64>,
    maybe_left: Option<f64>,
    maybe_right: Option<f64>,
}

impl<'a> Split<'a> {

    /// Construct a default Canvas Split.
    pub fn new(id: CanvasId) -> Split<'a> {
        Split {
            id: id,
            maybe_splits: None,
            maybe_length: None,
            //maybe_adjustable: None,
            style: Style::new(),
        }
    }

    /// Set the dimension of the Split.
    pub fn length(mut self, length: Length) -> Split<'a> {
        self.maybe_length = Some(length);
        self
    }

    /// Set the child Canvas Splits of the current Canvas flowing in a given direction.
    pub fn flow(mut self, dir: Direction, splits: &'a [Split<'a>]) -> Split<'a> {
        self.maybe_splits = Some((dir, splits));
        self
    }

    /// Set the child Canvasses flowing downwards.
    pub fn flow_down(self, splits: &'a [Split<'a>]) -> Split<'a> {
        self.flow(Direction::Down, splits)
    }

    /// Set the child Canvasses flowing upwards.
    pub fn flow_up(self, splits: &'a [Split<'a>]) -> Split<'a> {
        self.flow(Direction::Up, splits)
    }

    /// Set the child Canvasses flowing to the right.
    pub fn flow_right(self, splits: &'a [Split<'a>]) -> Split<'a> {
        self.flow(Direction::Right, splits)
    }

    /// Set the child Canvasses flowing to the left.
    pub fn flow_left(self, splits: &'a [Split<'a>]) -> Split<'a> {
        self.flow(Direction::Left, splits)
    }

    /// Set the padding from the left edge.
    pub fn pad_left(mut self, pad: Scalar) -> Split<'a> {
        self.style.padding.maybe_left = Some(pad);
        self
    }

    /// Set the padding from the right edge.
    pub fn pad_right(mut self, pad: Scalar) -> Split<'a> {
        self.style.padding.maybe_right = Some(pad);
        self
    }

    /// Set the padding from the top edge.
    pub fn pad_top(mut self, pad: Scalar) -> Split<'a> {
        self.style.padding.maybe_top = Some(pad);
        self
    }

    /// Set the padding from the bottom edge.
    pub fn pad_bottom(mut self, pad: Scalar) -> Split<'a> {
        self.style.padding.maybe_bottom = Some(pad);
        self
    }

    /// Set the padding for all edges.
    pub fn pad(self, pad: Scalar) -> Split<'a> {
        self.pad_left(pad).pad_right(pad).pad_top(pad).pad_bottom(pad)
    }

    /// Set the margin from the left edge.
    pub fn margin_left(mut self, pad: Scalar) -> Split<'a> {
        self.style.margin.maybe_left = Some(pad);
        self
    }

    /// Set the margin from the right edge.
    pub fn margin_right(mut self, pad: Scalar) -> Split<'a> {
        self.style.margin.maybe_right = Some(pad);
        self
    }

    /// Set the margin from the top edge.
    pub fn margin_top(mut self, pad: Scalar) -> Split<'a> {
        self.style.margin.maybe_top = Some(pad);
        self
    }

    /// Set the margin from the bottom edge.
    pub fn margin_bottom(mut self, pad: Scalar) -> Split<'a> {
        self.style.margin.maybe_bottom = Some(pad);
        self
    }

    /// Set the margin for all edges.
    pub fn margin(self, pad: Scalar) -> Split<'a> {
        self.margin_left(pad).margin_right(pad).margin_top(pad).margin_bottom(pad)
    }

    /// Store the Canvas and it's children within the `Ui`. Each Canvas can be accessed via it's
    /// unique identifier `CanvasId`.
    pub fn set<C>(self, ui: &mut Ui<C>) {
        let dim = [ui.win_w as f64, ui.win_h as f64];
        self.into_ui(dim, [0.0, 0.0], ui);
    }

    /// Construct a Canvas from a Split.
    fn into_ui<C>(&self, dim: Dimensions, xy: Point, ui: &mut Ui<C>) {
        use elmesque::form::{rect, collage};
        use vecmath::{vec2_add, vec2_sub};

        let Split { id, ref maybe_splits, ref style, .. } = *self;

        let color = style.color(&ui.theme);
        let frame_color = style.frame_color(&ui.theme);
        let frame = style.frame(&ui.theme);
        let pad = style.padding(&ui.theme);
        let mgn = style.margin(&ui.theme);

        let mgn_offset = [(mgn.left - mgn.right), (mgn.bottom - mgn.top)];
        let dim = vec2_sub(dim, [mgn.left + mgn.right, mgn.top + mgn.bottom]);
        let frame_dim = vec2_sub(dim, [frame * 2.0; 2]);
        let pad_offset = [(pad.bottom - pad.top), (pad.left - pad.right)];
        let pad_dim = vec2_sub(frame_dim, [pad.left + pad.right, pad.top + pad.bottom]);

        // Offset xy so that it is in the center of the given margin.
        let xy = vec2_add(xy, mgn_offset);

        if let Some((direction, splits)) = *maybe_splits {
            use position::{align_top_of, align_bottom_of, align_left_of, align_right_of};

            let mut stuck_length: f64 = 0.0;
            // Offset xy so that it is in the center of the padded area.
            let xy = vec2_add(xy, pad_offset);
            let mut num = splits.len();
            for s in splits.iter() {
                match s.maybe_length {
                    Some(l) => {
                        stuck_length += l;
                        num -= 1;
                    },
                    _ => {}
                }
            }

            let split_dim = match num {
                0 => [0.0, 0.0],
                1 => pad_dim,
                _ => match direction {
                    Direction::Up   | Direction::Down  => [pad_dim[0], (pad_dim[1] - stuck_length) / num as f64],
                    Direction::Left | Direction::Right => [(pad_dim[0] - stuck_length) / num as f64, pad_dim[1]],
                },
            };

            let mut cur_xy = xy;

            for split in splits.iter() {
                let split_dim = match split.maybe_length {
                    Some(len) => {
                        match direction {
                            Direction::Up   | Direction::Down  => [pad_dim[0], len],
                            Direction::Left | Direction::Right => [len, pad_dim[1]],
                        }
                    },
                    None => split_dim
                };
                split.into_ui(split_dim, vec2_add(cur_xy, match direction {
                    Direction::Up    => [0.0, xy[1] + align_bottom_of(pad_dim[1], split_dim[1])],
                    Direction::Down  => [0.0, xy[1] + align_top_of(pad_dim[1], split_dim[1])],
                    Direction::Left  => [align_right_of(pad_dim[0], split_dim[0]), 0.0],
                    Direction::Right => [align_left_of(pad_dim[0], split_dim[0]), 0.0],
                }), ui);

                cur_xy = vec2_add(cur_xy, match split.maybe_length {
                    Some(len) => {
                        match direction {
                            Direction::Up    => [0.0, len],
                            Direction::Down  => [0.0, -len],
                            Direction::Left  => [-len, 0.0],
                            Direction::Right => [len, 0.0],
                        }
                    },
                    None => {
                        match direction {
                            Direction::Up    => [0.0, split_dim[1]],
                            Direction::Down  => [0.0, -split_dim[1]],
                            Direction::Left  => [-split_dim[0], 0.0],
                            Direction::Right => [split_dim[0], 0.0],
                        }
                    }
                });
            }
        }

        let frame_form = rect(dim[0], dim[1]).filled(frame_color);
        let inner_form = rect(frame_dim[0], frame_dim[1]).filled(color);
        let form_chain = Some(frame_form).into_iter()
            .chain(Some(inner_form).into_iter())
            .map(|form| form.shift(xy[0], xy[1]));

        let element = collage(frame_dim[0] as i32, frame_dim[1] as i32, form_chain.collect());

        let widget_area_xy = xy;
        let widget_area_dim = dim;

        ui::update_canvas(ui, id, Kind::Split(State), xy, widget_area_xy,
                          widget_area_dim, pad, Some(element));
    }

}

impl Style {

    /// Construct a default Style.
    pub fn new() -> Style {
        Style {
            maybe_frame: None,
            maybe_frame_color: None,
            maybe_color: None,
            padding: Padding::new(),
            margin: Margin::new(),
        }
    }

    /// Get the color for the Split's Element.
    pub fn color(&self, theme: &Theme) -> Color {
        self.maybe_color.or(theme.maybe_canvas_split.as_ref().map(|style| {
            style.maybe_color.unwrap_or(theme.background_color)
        })).unwrap_or(theme.background_color)
    }

    /// Get the frame for an Element.
    pub fn frame(&self, theme: &Theme) -> f64 {
        self.maybe_frame.or(theme.maybe_canvas_split.as_ref().map(|style| {
            style.maybe_frame.unwrap_or(theme.frame_width)
        })).unwrap_or(theme.frame_width)
    }

    /// Get the frame Color for an Element.
    pub fn frame_color(&self, theme: &Theme) -> Color {
        self.maybe_frame_color.or(theme.maybe_canvas_split.as_ref().map(|style| {
            style.maybe_frame_color.unwrap_or(theme.frame_color)
        })).unwrap_or(theme.frame_color)
    }

    /// Get the Padding for the Canvas Split.
    pub fn padding(&self, theme: &Theme) -> position::Padding {
        position::Padding {
            top: self.padding.maybe_top.or(theme.maybe_canvas_split.as_ref().map(|style| {
                style.padding.maybe_top.unwrap_or(theme.padding.top)
            })).unwrap_or(theme.padding.top),
            bottom: self.padding.maybe_bottom.or(theme.maybe_canvas_split.as_ref().map(|style| {
                style.padding.maybe_bottom.unwrap_or(theme.padding.bottom)
            })).unwrap_or(theme.padding.bottom),
            left: self.padding.maybe_left.or(theme.maybe_canvas_split.as_ref().map(|style| {
                style.padding.maybe_left.unwrap_or(theme.padding.left)
            })).unwrap_or(theme.padding.left),
            right: self.padding.maybe_right.or(theme.maybe_canvas_split.as_ref().map(|style| {
                style.padding.maybe_right.unwrap_or(theme.padding.right)
            })).unwrap_or(theme.padding.right),
        }
    }

    /// Get the Margin for the Canvas Split.
    pub fn margin(&self, theme: &Theme) -> position::Margin {
        position::Margin {
            top: self.margin.maybe_top.or(theme.maybe_canvas_split.as_ref().map(|style| {
                style.margin.maybe_top.unwrap_or(theme.margin.top)
            })).unwrap_or(theme.margin.top),
            bottom: self.margin.maybe_bottom.or(theme.maybe_canvas_split.as_ref().map(|style| {
                style.margin.maybe_bottom.unwrap_or(theme.margin.bottom)
            })).unwrap_or(theme.margin.bottom),
            left: self.margin.maybe_left.or(theme.maybe_canvas_split.as_ref().map(|style| {
                style.margin.maybe_left.unwrap_or(theme.margin.left)
            })).unwrap_or(theme.margin.left),
            right: self.margin.maybe_right.or(theme.maybe_canvas_split.as_ref().map(|style| {
                style.margin.maybe_right.unwrap_or(theme.margin.right)
            })).unwrap_or(theme.margin.right),
        }
    }

}

impl Padding {
    /// Construct a defualt Padding.
    pub fn new() -> Padding {
        Padding {
            maybe_top: None,
            maybe_bottom: None,
            maybe_left: None,
            maybe_right: None,
        }
    }
}

impl Margin {
    /// Construct a defualt Margin.
    pub fn new() -> Margin {
        Margin {
            maybe_top: None,
            maybe_bottom: None,
            maybe_left: None,
            maybe_right: None,
        }
    }
}

impl<'a> ::color::Colorable for Split<'a> {
    fn color(mut self, color: Color) -> Self {
        self.style.maybe_color = Some(color);
        self
    }
}

impl<'a> ::frame::Frameable for Split<'a> {
    fn frame(mut self, width: f64) -> Self {
        self.style.maybe_frame = Some(width);
        self
    }
    fn frame_color(mut self, color: Color) -> Self {
        self.style.maybe_frame_color = Some(color);
        self
    }
}

<|endoftext|>


<commit_before>
use std::fs::File;
use byteorder::{BigEndian, ReadBytesExt};
use std::io;
use std::io::{Error, ErrorKind, Seek, Read};

const HUNK_HEADER: u32 = 1011;
// hunk types
const HUNK_UNIT: u32 = 999;
const HUNK_NAME: u32 = 1000;
const HUNK_CODE: u32 = 1001;
const HUNK_DATA: u32 = 1002;
const HUNK_BSS: u32 = 1003;
const HUNK_RELOC32: u32 = 1004;
const HUNK_DEBUG: u32 = 1009;
const HUNK_SYMBOL: u32 = 1008;
const HUNK_END: u32 = 1010;

/*
   const HUNK_ABSRELOC32: u32 = HUNK_RELOC32;
   const HUNK_RELOC16: u32 = 1005;
   const HUNK_RELRELOC16 :u32 = HUNK_RELOC16;
   const HUNK_RELOC8: u32 = 1006;
   const HUNK_RELRELOC8: u32 = HUNK_RELOC8;

   const HUNK_OVERLAY: u32 = 1013;
   const HUNK_BREAK: u32 = 1014;

   const HUNK_DREL32: u32 = 1015;
   const HUNK_DREL16: u32 = 1016;
   const HUNK_DREL8: u32 = 1017;

   const HUNK_LIB: u32 = 1018;
   const HUNK_INDEX: u32 = 1019;
   */

/*
//
// Note: V37 LoadSeg uses 1015 (HUNK_DREL32) by mistake.  This will continue
// to be supported in future versions, since HUNK_DREL32 is illegal in load files
// anyways.  Future versions will support both 1015 and 1020, though anything
// that should be usable under V37 should use 1015.
//

const HUNK_RELOC32SHORT:u32 = 1020;

// see ext_xxx below.  New for V39 (note that LoadSeg only handles RELRELOC32).
const HUNK_RELRELOC32:u32 = 1021;
const HUNK_ABSRELOC16:u32 = 1022;

//
// Any hunks that have the HUNKB_ADVISORY bit set will be ignored if they
// aren't understood.  When ignored, they're treated like HUNK_DEBUG hunks.
// NOTE: this handling of HUNKB_ADVISORY started as of V39 dos.library!  If
// lading such executables is attempted under <V39 dos, it will fail with a
// bad hunk type.
//

const HUNKB_ADVISORY: u32 = 29;

// hunk_ext sub-type
const EXT_SYMB:u32 = 0; // table
const EXT_DEF: u32 = 1;	// relocatable definition
const EXT_ABS: u32 = 2;	// Absolute definition
const EXT_RES: u32 = 3;	// no longer supported
const EXT_REF32: u32 = 129;	// 32 bit absolute reference to symbol
const EXT_ABSREF32: u32 = EXT_REF32;
const EXT_COMMON: u32 = 130;	// 32 bit absolute reference to COMMON block
const EXT_ABSCOMMON: u32 = EXT_COMMON;
const EXT_REF16: u32 = 131;	// 16 bit PC-relative reference to symbol
const EXT_RELREF16: u32 = EXT_REF16;
const EXT_REF8: u32 = 132;	//  8 bit PC-relative reference to symbol
const EXT_RELREF8: u32 = EXT_REF8;
const EXT_DEXT32: u32 = 133; // 32 bit data relative reference
const EXT_DEXT16: u32 = 134; // 16 bit data relative reference
const EXT_DEXT8: u32 = 135; // 8 bit data relative reference

// These are to support some of the '020 and up modes that are rarely used
const EXT_RELREF32:u32 = 136;	// 32 bit PC-relative reference to symbol
const EXT_RELCOMMON:u32 = 137;	// 32 bit PC-relative reference to COMMON block

// for completeness... All 680x0's support this
const EXT_ABSREF16:u32 = 138;	// 16 bit absolute reference to symbol

// this only exists on '020's and above, in the (d8,An,Xn) address mode
const EXT_ABSREF8:u32 = 139; //8 bit absolute reference to symbol

*/

const HUNKF_CHIP: u32 = 1 << 30;
const HUNKF_FAST: u32 = 1 << 31;

pub struct HunkParser;

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum HunkType {
    Code,
    Data,
    Bss,
}

pub struct RelocInfo32 {
    pub target: usize,
    pub data: Vec<u32>,
}

pub struct Hunk {
    pub mem_type: MemoryType,
    pub hunk_type: HunkType,
    pub alloc_size: usize,
    pub data_size: usize,
    pub code_data: Option<Vec<u8>>,
    pub reloc_32: Option<Vec<RelocInfo32>>,
}

#[derive(Clone, Copy, Debug)]
pub enum MemoryType {
    Any,
    Chip,
    Fast,
}

struct SizesTypes {
    mem_type: MemoryType,
    size: usize,
}

impl HunkParser {
    fn skip_hunk(file: &mut File, name: &'static str) -> io::Result<()> {
        println!("Skipping {}\n", name);
        let seek_offset = try!(file.read_u32::<BigEndian>());
        file.seek(io::SeekFrom::Current(seek_offset as i64)).map(|_|())
    }

    fn get_size_type(t: u32) -> (usize, MemoryType) {
        let size = (t & 0x0fffffff) * 4;
        let mem_t = t & 0xf0000000;
        let mem_type = match mem_t {
            HUNKF_CHIP => MemoryType::Chip,
            HUNKF_FAST => MemoryType::Fast,
            _ => MemoryType::Any,
        };

        (size as usize, mem_type)
    }

    fn parse_bss(hunk: &mut Hunk, file: &mut File) -> io::Result<()> {
        let (size, mem_type) = Self::get_size_type(try!(file.read_u32::<BigEndian>()));
        hunk.hunk_type = HunkType::Bss;
        hunk.data_size = size;
        hunk.mem_type = mem_type;
        Ok(())
    }

    fn parse_code_or_data(hunk_type: HunkType, hunk: &mut Hunk, file: &mut File) -> io::Result<()> {
        let (size, mem_type) = Self::get_size_type(try!(file.read_u32::<BigEndian>()));
        let mut code_data: Vec<u8> = vec![0; size];

        hunk.data_size = size;
        hunk.hunk_type = hunk_type;
        hunk.mem_type = mem_type;

        try!(file.read(&mut code_data));

        hunk.code_data = Some(code_data);

        Ok(())
    }

    fn parse_symbol(file: &mut File) -> io::Result<()> {
        let mut sym_len = try!(file.read_u32::<BigEndian>()) * 4;

        while sym_len > 0 {
            try!(file.seek(io::SeekFrom::Current((sym_len + 4) as i64)).map(|_| ()));
            sym_len = try!(file.read_u32::<BigEndian>()) * 4;
        }

        Ok(())
    }

    fn parse_reloc32(hunk: &mut Hunk, file: &mut File) -> io::Result<()> {
        let mut relocs = Vec::<RelocInfo32>::new();

        loop {
            let count = try!(file.read_u32::<BigEndian>()) as usize;

            if count == 0 {
                break;
            }

            let target = try!(file.read_u32::<BigEndian>()) as usize;

            let mut reloc = RelocInfo32 {
                target: target,
                data: Vec::<u32>::with_capacity(count),
            };

            for _ in 0..count {
                reloc.data.push(try!(file.read_u32::<BigEndian>()));
            }

            relocs.push(reloc);
        }

        hunk.reloc_32 = Some(relocs);

        Ok(())
    }

    fn fill_hunk(hunk: &mut Hunk, file: &mut File) -> io::Result<()> {
        loop {
            let hunk_type = try!(file.read_u32::<BigEndian>());

            match hunk_type {
                HUNK_UNIT => { try!(Self::skip_hunk(file, "HUNK_UNIT")) }
                HUNK_NAME => { try!(Self::skip_hunk(file, "HUNK_NAME")) }
                HUNK_DEBUG => { try!(Self::skip_hunk(file, "HUNK_DEBUG")) }
                HUNK_CODE => { try!(Self::parse_code_or_data(HunkType::Code, hunk, file)) }
                HUNK_DATA => { try!(Self::parse_code_or_data(HunkType::Data, hunk, file)) }
                HUNK_BSS => { try!(Self::parse_bss(hunk, file)) }
                HUNK_RELOC32 => { try!(Self::parse_reloc32(hunk, file)) }
                HUNK_SYMBOL => { try!(Self::parse_symbol(file)) }
                HUNK_END => {
                    return Ok(());
                }

                _ => {
                    return Err(Error::new(ErrorKind::Other, "Unsupported hunk"));
                }
            }
        }
    }

    pub fn parse_file(filename: &str) -> Result<Vec<Hunk>, io::Error> {
        //let mut index = 0;

        let mut file = try!(File::open(filename));

        let hunk_header = try!(file.read_u32::<BigEndian>());
        if hunk_header != HUNK_HEADER  {
            return Err(Error::new(ErrorKind::Other, "Unable to find correct HUNK_HEADER"));
        };

        // Skip header/string section
        try!(file.read_u32::<BigEndian>());

        let table_size = try!(file.read_u32::<BigEndian>()) as i32;
        let first_hunk = try!(file.read_u32::<BigEndian>()) as i32;
        let last_hunk = try!(file.read_u32::<BigEndian>()) as i32;

        if table_size < 0 || first_hunk < 0 || last_hunk < 0 {
            return Err(Error::new(ErrorKind::Other, "Invalid sizes for hunks"));
        }

        let hunk_count = (last_hunk - first_hunk + 1) as usize;

        let mut hunk_table = Vec::with_capacity(hunk_count);

        for _ in 0..hunk_count {
            let (size, mem_type) = Self::get_size_type(try!(file.read_u32::<BigEndian>()));
            hunk_table.push(SizesTypes {
                mem_type: mem_type,
                size: size
            });
        }

        let mut hunks = Vec::with_capacity(hunk_count);

        for i in 0..hunk_count {
            let mut hunk = Hunk {
                mem_type: hunk_table[i].mem_type,
                    hunk_type: HunkType::Bss,
                    alloc_size: hunk_table[i].size as usize,
                    data_size: 0,
                    code_data: None,
                    reloc_32: None,
            };

            try!(Self::fill_hunk(&mut hunk, &mut file));

            hunks.push(hunk);
        }

        // dump info

        //for hunk in hunks {
        //   println!("type {:?} - size {} - alloc_size {}", hunk.hunk_type, hunk.data_size, hunk.alloc_size);
        //}

        //println!("b {}", hunk_header);
        Ok(hunks)
    }
}
<commit_msg>Use new-style syntax for try!(…)<commit_after>
use std::fs::File;
use byteorder::{BigEndian, ReadBytesExt};
use std::io;
use std::io::{Error, ErrorKind, Seek, Read};

const HUNK_HEADER: u32 = 1011;
// hunk types
const HUNK_UNIT: u32 = 999;
const HUNK_NAME: u32 = 1000;
const HUNK_CODE: u32 = 1001;
const HUNK_DATA: u32 = 1002;
const HUNK_BSS: u32 = 1003;
const HUNK_RELOC32: u32 = 1004;
const HUNK_DEBUG: u32 = 1009;
const HUNK_SYMBOL: u32 = 1008;
const HUNK_END: u32 = 1010;

/*
   const HUNK_ABSRELOC32: u32 = HUNK_RELOC32;
   const HUNK_RELOC16: u32 = 1005;
   const HUNK_RELRELOC16 :u32 = HUNK_RELOC16;
   const HUNK_RELOC8: u32 = 1006;
   const HUNK_RELRELOC8: u32 = HUNK_RELOC8;

   const HUNK_OVERLAY: u32 = 1013;
   const HUNK_BREAK: u32 = 1014;

   const HUNK_DREL32: u32 = 1015;
   const HUNK_DREL16: u32 = 1016;
   const HUNK_DREL8: u32 = 1017;

   const HUNK_LIB: u32 = 1018;
   const HUNK_INDEX: u32 = 1019;
   */

/*
//
// Note: V37 LoadSeg uses 1015 (HUNK_DREL32) by mistake.  This will continue
// to be supported in future versions, since HUNK_DREL32 is illegal in load files
// anyways.  Future versions will support both 1015 and 1020, though anything
// that should be usable under V37 should use 1015.
//

const HUNK_RELOC32SHORT:u32 = 1020;

// see ext_xxx below.  New for V39 (note that LoadSeg only handles RELRELOC32).
const HUNK_RELRELOC32:u32 = 1021;
const HUNK_ABSRELOC16:u32 = 1022;

//
// Any hunks that have the HUNKB_ADVISORY bit set will be ignored if they
// aren't understood.  When ignored, they're treated like HUNK_DEBUG hunks.
// NOTE: this handling of HUNKB_ADVISORY started as of V39 dos.library!  If
// lading such executables is attempted under <V39 dos, it will fail with a
// bad hunk type.
//

const HUNKB_ADVISORY: u32 = 29;

// hunk_ext sub-type
const EXT_SYMB:u32 = 0; // table
const EXT_DEF: u32 = 1;	// relocatable definition
const EXT_ABS: u32 = 2;	// Absolute definition
const EXT_RES: u32 = 3;	// no longer supported
const EXT_REF32: u32 = 129;	// 32 bit absolute reference to symbol
const EXT_ABSREF32: u32 = EXT_REF32;
const EXT_COMMON: u32 = 130;	// 32 bit absolute reference to COMMON block
const EXT_ABSCOMMON: u32 = EXT_COMMON;
const EXT_REF16: u32 = 131;	// 16 bit PC-relative reference to symbol
const EXT_RELREF16: u32 = EXT_REF16;
const EXT_REF8: u32 = 132;	//  8 bit PC-relative reference to symbol
const EXT_RELREF8: u32 = EXT_REF8;
const EXT_DEXT32: u32 = 133; // 32 bit data relative reference
const EXT_DEXT16: u32 = 134; // 16 bit data relative reference
const EXT_DEXT8: u32 = 135; // 8 bit data relative reference

// These are to support some of the '020 and up modes that are rarely used
const EXT_RELREF32:u32 = 136;	// 32 bit PC-relative reference to symbol
const EXT_RELCOMMON:u32 = 137;	// 32 bit PC-relative reference to COMMON block

// for completeness... All 680x0's support this
const EXT_ABSREF16:u32 = 138;	// 16 bit absolute reference to symbol

// this only exists on '020's and above, in the (d8,An,Xn) address mode
const EXT_ABSREF8:u32 = 139; //8 bit absolute reference to symbol

*/

const HUNKF_CHIP: u32 = 1 << 30;
const HUNKF_FAST: u32 = 1 << 31;

pub struct HunkParser;

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum HunkType {
    Code,
    Data,
    Bss,
}

pub struct RelocInfo32 {
    pub target: usize,
    pub data: Vec<u32>,
}

pub struct Hunk {
    pub mem_type: MemoryType,
    pub hunk_type: HunkType,
    pub alloc_size: usize,
    pub data_size: usize,
    pub code_data: Option<Vec<u8>>,
    pub reloc_32: Option<Vec<RelocInfo32>>,
}

#[derive(Clone, Copy, Debug)]
pub enum MemoryType {
    Any,
    Chip,
    Fast,
}

struct SizesTypes {
    mem_type: MemoryType,
    size: usize,
}

impl HunkParser {
    fn skip_hunk(file: &mut File, name: &'static str) -> io::Result<()> {
        println!("Skipping {}\n", name);
        let seek_offset = file.read_u32::<BigEndian>()?;
        file.seek(io::SeekFrom::Current(seek_offset as i64)).map(|_|())
    }

    fn get_size_type(t: u32) -> (usize, MemoryType) {
        let size = (t & 0x0fffffff) * 4;
        let mem_t = t & 0xf0000000;
        let mem_type = match mem_t {
            HUNKF_CHIP => MemoryType::Chip,
            HUNKF_FAST => MemoryType::Fast,
            _ => MemoryType::Any,
        };

        (size as usize, mem_type)
    }

    fn parse_bss(hunk: &mut Hunk, file: &mut File) -> io::Result<()> {
        let (size, mem_type) = Self::get_size_type(file.read_u32::<BigEndian>()?);
        hunk.hunk_type = HunkType::Bss;
        hunk.data_size = size;
        hunk.mem_type = mem_type;
        Ok(())
    }

    fn parse_code_or_data(hunk_type: HunkType, hunk: &mut Hunk, file: &mut File) -> io::Result<()> {
        let (size, mem_type) = Self::get_size_type(file.read_u32::<BigEndian>()?);
        let mut code_data: Vec<u8> = vec![0; size];

        hunk.data_size = size;
        hunk.hunk_type = hunk_type;
        hunk.mem_type = mem_type;

        file.read(&mut code_data)?;

        hunk.code_data = Some(code_data);

        Ok(())
    }

    fn parse_symbol(file: &mut File) -> io::Result<()> {
        let mut sym_len = file.read_u32::<BigEndian>()? * 4;

        while sym_len > 0 {
            file.seek(io::SeekFrom::Current((sym_len + 4) as i64)).map(|_| ())?;
            sym_len = file.read_u32::<BigEndian>()? * 4;
        }

        Ok(())
    }

    fn parse_reloc32(hunk: &mut Hunk, file: &mut File) -> io::Result<()> {
        let mut relocs = Vec::<RelocInfo32>::new();

        loop {
            let count = file.read_u32::<BigEndian>()? as usize;

            if count == 0 {
                break;
            }

            let target = file.read_u32::<BigEndian>()? as usize;

            let mut reloc = RelocInfo32 {
                target: target,
                data: Vec::<u32>::with_capacity(count),
            };

            for _ in 0..count {
                reloc.data.push(file.read_u32::<BigEndian>()?);
            }

            relocs.push(reloc);
        }

        hunk.reloc_32 = Some(relocs);

        Ok(())
    }

    fn fill_hunk(hunk: &mut Hunk, file: &mut File) -> io::Result<()> {
        loop {
            let hunk_type = file.read_u32::<BigEndian>()?;

            match hunk_type {
                HUNK_UNIT => { Self::skip_hunk(file, "HUNK_UNIT")? }
                HUNK_NAME => { Self::skip_hunk(file, "HUNK_NAME")? }
                HUNK_DEBUG => { Self::skip_hunk(file, "HUNK_DEBUG")? }
                HUNK_CODE => { Self::parse_code_or_data(HunkType::Code, hunk, file)? }
                HUNK_DATA => { Self::parse_code_or_data(HunkType::Data, hunk, file)? }
                HUNK_BSS => { Self::parse_bss(hunk, file)? }
                HUNK_RELOC32 => { Self::parse_reloc32(hunk, file)? }
                HUNK_SYMBOL => { Self::parse_symbol(file)? }
                HUNK_END => {
                    return Ok(());
                }

                _ => {
                    return Err(Error::new(ErrorKind::Other, "Unsupported hunk"));
                }
            }
        }
    }

    pub fn parse_file(filename: &str) -> Result<Vec<Hunk>, io::Error> {
        //let mut index = 0;

        let mut file = File::open(filename)?;

        let hunk_header = file.read_u32::<BigEndian>()?;
        if hunk_header != HUNK_HEADER  {
            return Err(Error::new(ErrorKind::Other, "Unable to find correct HUNK_HEADER"));
        };

        // Skip header/string section
        file.read_u32::<BigEndian>()?;

        let table_size = file.read_u32::<BigEndian>()? as i32;
        let first_hunk = file.read_u32::<BigEndian>()? as i32;
        let last_hunk = file.read_u32::<BigEndian>()? as i32;

        if table_size < 0 || first_hunk < 0 || last_hunk < 0 {
            return Err(Error::new(ErrorKind::Other, "Invalid sizes for hunks"));
        }

        let hunk_count = (last_hunk - first_hunk + 1) as usize;

        let mut hunk_table = Vec::with_capacity(hunk_count);

        for _ in 0..hunk_count {
            let (size, mem_type) = Self::get_size_type(file.read_u32::<BigEndian>()?);
            hunk_table.push(SizesTypes {
                mem_type: mem_type,
                size: size
            });
        }

        let mut hunks = Vec::with_capacity(hunk_count);

        for i in 0..hunk_count {
            let mut hunk = Hunk {
                mem_type: hunk_table[i].mem_type,
                    hunk_type: HunkType::Bss,
                    alloc_size: hunk_table[i].size as usize,
                    data_size: 0,
                    code_data: None,
                    reloc_32: None,
            };

            Self::fill_hunk(&mut hunk, &mut file)?;

            hunks.push(hunk);
        }

        // dump info

        //for hunk in hunks {
        //   println!("type {:?} - size {} - alloc_size {}", hunk.hunk_type, hunk.data_size, hunk.alloc_size);
        //}

        //println!("b {}", hunk_header);
        Ok(hunks)
    }
}
<|endoftext|>


<commit_before>fn spiral_index(x: i32, y: i32) -> i32 {
    let mut p: i32;

    if y * y >= x * x {
        p = 4 * y * y - y - x;
        if y < x {
            p -= 2 * (y - x);
        }
    } else {
        p = 4 * x * x - y - x;
        if y < x {
            p += 2 * (y - x);
        }
    }

    p
}

pub fn spiral_matrix(size: u32) -> Vec<Vec<u32>> {
    let mut result = Vec::new();

    if size == 0 {
        return result;
    }

    let width: i32 = size as i32;

    let sx = if width % 2 == 1 {
        width / 2
    } else {
        (1 - width) / 2
    };
    let ex = if width % 2 == 1 {
        (1 - width) / 2 - 1
    } else {
        width / 2 + 1
    };
    let dx = if width % 2 == 1 { -1 } else { 1 };
    let sy = if width % 2 == 1 {
        (1 - width) / 2
    } else {
        width / 2
    };
    let ey = if width % 2 == 1 {
        width / 2 + 1
    } else {
        (1 - width) / 2 - 1
    };
    let dy = if width % 2 == 1 { 1 } else { -1 };

    let mut y = sy;
    while y != ey {
        let mut v = Vec::new();

        let mut x = sx;
        while x != ex {
            let r = width * width - spiral_index(x, y);
            v.push(r as u32);
            x += dx;
        }

        result.push(v);
        y += dy;
    }

    result
}
<commit_msg>Improve the solution<commit_after>//
// This is smart but slow
//
//fn spiral(width: u32, height: u32, x: u32, y: u32) -> u32 {
//    if y == 0 {
//        x + 1
//    } else {
//        width + spiral(height - 1, width, y - 1, width - x - 1)
//    }
//}
//
//pub fn spiral_matrix(size: u32) -> Vec<Vec<u32>> {
//    (0..size)
//        .map(|y| (0..size).map(|x| spiral(size, size, x, y)).collect())
//        .collect()
//}

pub fn spiral_matrix(size: u32) -> Vec<Vec<u32>> {
    if size == 0 {
        return Vec::new();
    }

    let mut result = vec![vec![0; size as usize]; size as usize];

    let mut left = 0usize;
    let mut top = 0usize;
    let mut right = size as usize;
    let mut bottom = size as usize;

    let mut value = 1;

    while left < right && top < bottom {
        // fill top line
        for x in left..right {
            result[top][x] = value;

            value += 1;
        }
        top += 1;

        // fill right line
        for y in top..bottom {
            result[y][right - 1] = value;

            value += 1;
        }
        right -= 1;

        // fill bottom lime
        for x in (left..right).rev() {
            result[bottom - 1][x] = value;

            value += 1;
        }
        bottom -= 1;

        // fill left line
        for y in (top..bottom).rev() {
            result[y][left] = value;

            value += 1;
        }
        left += 1;
    }

    result
}
<|endoftext|>