<commit_before>use seed::prelude::*;
use crate::Msg;

mod perfects_utils {
	pub struct Perfect<'a> {
		pub n: u64,
		pub p: &'a str,
		pub digits: u64,
		pub discovery: &'a str,
	}

	pub fn perfects<'a>() -> Vec<Perfect<'a>> {
        vec![
			Perfect {n: 50, p: "277232916 × (277232917-1)", digits: 46498850, discovery: "2017 Jonathan Pace, George Woltman, Scott Kurowski, Aaron Blosser, et al.." },
			Perfect {n: 49, p: "274207280 × (274207281-1)", digits: 44677235, discovery: "2016 Cooper, Woltman, Kurowski, Blosser et al." },
			Perfect {n: 48, p: "257885160 × (257885161-1)", digits: 34850340, discovery: "2013 Cooper, Woltman, Kurowski, et al." },
			Perfect {n: 47, p: "243112608 × (243112609-1)", digits: 25956377, discovery: "2008 Smith, Woltman, Kurowski, et al." },
			Perfect {n: 46, p: "242643800 × (242643801-1)", digits: 42643801, discovery: "2009 Strindmo, Woltman, Kurowski, et al." },
			Perfect {n: 45, p: "237156666 × (237156667-1)", digits: 22370543, discovery: "2008 Elvenich, Woltman, Kurowski, et al." },
			Perfect {n: 44, p: "232582656 × (232582657-1)", digits: 19616714, discovery: "2006 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 43, p: "230402456 × (230402457-1)", digits: 18304103, discovery: "2005 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 42, p: "225964950 × (225964951-1)", digits: 15632458, discovery: "2005 Nowak, Woltman, Kurowski, et. al." },
			Perfect {n: 41, p: "224036582 × (224036583-1)", digits: 14471465, discovery: "2004 Findley, Woltman, Kurowski, et. al." },
			Perfect {n: 40, p: "220996010 × (220996011-1)", digits: 12640858, discovery: "2003 Shafer, Woltman, Kurowski, et. al." },
			Perfect {n: 39, p: "213466916 × (213466917-1)", digits: 8107892, discovery: "2001 Cameron, Woltman, Kurowski, et. al." },
			Perfect {n: 38, p: "26972592 × (26972593-1)", digits: 4197919, discovery: "1999 Hajratwala, Woltman, Kurowski, et. al." },
			Perfect {n: 37, p: "23021376 × (23021377-1)", digits: 1819050, discovery: "1998 Clarkson, Woltman, Kurowski, et. al." },
			Perfect {n: 36, p: "22976220 × (22976221-1)", digits: 1791864, discovery: "1997 Spence, Woltman, et. al." },
			Perfect {n: 35, p: "21398268 × (21398269-1)", digits: 841842, discovery: "1996 Armengaud, Woltman, et. al." },
			Perfect {n: 34, p: "21257786 × (21257787-1)", digits: 757263, discovery: "1996 Slowinski&Gage" },
			Perfect {n: 33, p: "2859432 × (2859433-1)", digits: 517430, discovery: "1994 Slowinski&Gage" },
			Perfect {n: 32, p: "2756838 × (2756839-1)", digits: 455663, discovery: "1992 Slowinski&Gage" },
			Perfect {n: 31, p: "2216090 × (2216091-1)", digits: 130100, discovery: "1985 Slowinski" },
			Perfect {n: 30, p: "2132048 × (2132049-1)", digits: 79502, discovery: "1983 Slowinski" },
			Perfect {n: 29, p: "2110502 × (2110503-1)", digits: 66530, discovery: "1988 Colquitt&Welsh" },
			Perfect {n: 28, p: "286242 × (286243-1)", digits: 51924, discovery: "1982 Slowinski" },
			Perfect {n: 27, p: "244496 × (244497-1)", digits: 26790, discovery: "1979 Nelson&Slowinski" },
			Perfect {n: 26, p: "223208 × (223209-1)", digits: 13973, discovery: "1979 Noll" },
			Perfect {n: 25, p: "221700 × (221701-1)", digits: 13066, discovery: "1978 Noll&Nickel" },
			Perfect {n: 24, p: "219936 × (219937-1)", digits: 12003, discovery: "1971 Tuckerman" },
			Perfect {n: 23, p: "211212 × (211213-1)", digits: 6751, discovery: "1963 Gillies" },
			Perfect {n: 22, p: "29940 × (29941-1)", digits: 5985, discovery: "1963 Gillies" },
			Perfect {n: 21, p: "29688 × (29689-1)", digits: 5834, discovery: "1963 Gillies" },
			Perfect {n: 20, p: "24422 × (24423-1)", digits: 2663, discovery: "1961 Hurwitz" },
			Perfect {n: 19, p: "24252 × (24253-1)", digits: 2561, discovery: "1961 Hurwitz" },
			Perfect {n: 18, p: "23216 × (23217-1)", digits: 1937, discovery: "1957 Riesel" },
			Perfect {n: 17, p: "22280 × (22281-1)", digits: 1373, discovery: "1952 Robinson" },
			Perfect {n: 16, p: "22202 × (22203-1)", digits: 1327, discovery: "1952 Robinson" },
			Perfect {n: 15, p: "21278 × (21279-1)", digits: 770, discovery: "1952 Robinson" },
			Perfect {n: 14, p: "2606 × (2607-1)", digits: 366, discovery: "1952 Robinson" },
			Perfect {n: 13, p: "2520 × (2521-1)", digits: 314, discovery: "1952 Robinson" },
			Perfect {n: 12, p: "2126 × (2127-1)", digits: 77, discovery: "1876 Lucas" },
			Perfect {n: 11, p: "2106 × (2107-1)", digits: 65, discovery: "1914 Powers" },
			Perfect {n: 10, p: "288 × (289-1)", digits: 54, discovery: "1911 Powers" },
			Perfect {n: 9, p: "260 × (261-1)", digits: 37, discovery: "1883 Pervushin" },
			Perfect {n: 8, p: "230 × (231-1)", digits: 19, discovery: "1772 Euler" },
			Perfect {n: 7, p: "218 × (219-1)", digits: 12, discovery: "1588 Cataldi" },
			Perfect {n: 6, p: "216 × (217-1)", digits: 10, discovery: "1588 Cataldi" },
			Perfect {n: 5, p: "212 × (213-1)", digits: 8, discovery: "1456 ?" },
			Perfect {n: 4, p: "26 × (27-1)", digits: 4, discovery: "?" },
			Perfect {n: 3, p: "24 × (25-1)", digits: 3, discovery: "?" },
			Perfect {n: 2, p: "22 × (23-1)", digits: 2, discovery: "?" },
			Perfect {n: 1, p: "21 × (23-1)", digits: 1, discovery: "?" },
		]
	}
}

pub fn render() -> seed::dom_types::Node<Msg> {
    let mut html = vec![];

    let perfects = perfects_utils::perfects();

    for n in 0..perfects.len() {
        let download_txt:String = vec!["https://static.bigprimes.net/archive/perfect/",&perfects[n].n.to_string(),".txt"].into_iter().collect();
        let download_zip:String = vec!["https://static.bigprimes.net/archive/perfect/",&perfects[n].n.to_string(),".zip"].into_iter().collect();
        html.push(
            tr![
                td![perfects[n].n.to_string()],//rank
                td![El::from_html(perfects[n].p)],//perfect number as a formula
                td![perfects[n].digits.to_string()],//digits in length
                td![perfects[n].discovery],//disocvery
                if perfects[n].n >= 25 {a![attrs!{At::Href => download_zip},"ZIP"]} else {a![attrs!{At::Href => download_txt},"TXT"]}//downloads
            ]
        );
    }

    div![
        h1!["The Perfect Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "perfecttable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}<commit_msg>Added unit tests for perfects_utils::perfects()<commit_after>use seed::prelude::*;
use crate::Msg;

mod perfects_utils {
	pub struct Perfect<'a> {
		pub n: u64,
		pub p: &'a str,
		pub digits: u64,
		pub discovery: &'a str,
	}

	pub fn perfects<'a>() -> Vec<Perfect<'a>> {
        vec![
			Perfect {n: 50, p: "277232916 × (277232917-1)", digits: 46498850, discovery: "2017 Jonathan Pace, George Woltman, Scott Kurowski, Aaron Blosser, et al.." },
			Perfect {n: 49, p: "274207280 × (274207281-1)", digits: 44677235, discovery: "2016 Cooper, Woltman, Kurowski, Blosser et al." },
			Perfect {n: 48, p: "257885160 × (257885161-1)", digits: 34850340, discovery: "2013 Cooper, Woltman, Kurowski, et al." },
			Perfect {n: 47, p: "243112608 × (243112609-1)", digits: 25956377, discovery: "2008 Smith, Woltman, Kurowski, et al." },
			Perfect {n: 46, p: "242643800 × (242643801-1)", digits: 42643801, discovery: "2009 Strindmo, Woltman, Kurowski, et al." },
			Perfect {n: 45, p: "237156666 × (237156667-1)", digits: 22370543, discovery: "2008 Elvenich, Woltman, Kurowski, et al." },
			Perfect {n: 44, p: "232582656 × (232582657-1)", digits: 19616714, discovery: "2006 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 43, p: "230402456 × (230402457-1)", digits: 18304103, discovery: "2005 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 42, p: "225964950 × (225964951-1)", digits: 15632458, discovery: "2005 Nowak, Woltman, Kurowski, et. al." },
			Perfect {n: 41, p: "224036582 × (224036583-1)", digits: 14471465, discovery: "2004 Findley, Woltman, Kurowski, et. al." },
			Perfect {n: 40, p: "220996010 × (220996011-1)", digits: 12640858, discovery: "2003 Shafer, Woltman, Kurowski, et. al." },
			Perfect {n: 39, p: "213466916 × (213466917-1)", digits: 8107892, discovery: "2001 Cameron, Woltman, Kurowski, et. al." },
			Perfect {n: 38, p: "26972592 × (26972593-1)", digits: 4197919, discovery: "1999 Hajratwala, Woltman, Kurowski, et. al." },
			Perfect {n: 37, p: "23021376 × (23021377-1)", digits: 1819050, discovery: "1998 Clarkson, Woltman, Kurowski, et. al." },
			Perfect {n: 36, p: "22976220 × (22976221-1)", digits: 1791864, discovery: "1997 Spence, Woltman, et. al." },
			Perfect {n: 35, p: "21398268 × (21398269-1)", digits: 841842, discovery: "1996 Armengaud, Woltman, et. al." },
			Perfect {n: 34, p: "21257786 × (21257787-1)", digits: 757263, discovery: "1996 Slowinski&Gage" },
			Perfect {n: 33, p: "2859432 × (2859433-1)", digits: 517430, discovery: "1994 Slowinski&Gage" },
			Perfect {n: 32, p: "2756838 × (2756839-1)", digits: 455663, discovery: "1992 Slowinski&Gage" },
			Perfect {n: 31, p: "2216090 × (2216091-1)", digits: 130100, discovery: "1985 Slowinski" },
			Perfect {n: 30, p: "2132048 × (2132049-1)", digits: 79502, discovery: "1983 Slowinski" },
			Perfect {n: 29, p: "2110502 × (2110503-1)", digits: 66530, discovery: "1988 Colquitt&Welsh" },
			Perfect {n: 28, p: "286242 × (286243-1)", digits: 51924, discovery: "1982 Slowinski" },
			Perfect {n: 27, p: "244496 × (244497-1)", digits: 26790, discovery: "1979 Nelson&Slowinski" },
			Perfect {n: 26, p: "223208 × (223209-1)", digits: 13973, discovery: "1979 Noll" },
			Perfect {n: 25, p: "221700 × (221701-1)", digits: 13066, discovery: "1978 Noll&Nickel" },
			Perfect {n: 24, p: "219936 × (219937-1)", digits: 12003, discovery: "1971 Tuckerman" },
			Perfect {n: 23, p: "211212 × (211213-1)", digits: 6751, discovery: "1963 Gillies" },
			Perfect {n: 22, p: "29940 × (29941-1)", digits: 5985, discovery: "1963 Gillies" },
			Perfect {n: 21, p: "29688 × (29689-1)", digits: 5834, discovery: "1963 Gillies" },
			Perfect {n: 20, p: "24422 × (24423-1)", digits: 2663, discovery: "1961 Hurwitz" },
			Perfect {n: 19, p: "24252 × (24253-1)", digits: 2561, discovery: "1961 Hurwitz" },
			Perfect {n: 18, p: "23216 × (23217-1)", digits: 1937, discovery: "1957 Riesel" },
			Perfect {n: 17, p: "22280 × (22281-1)", digits: 1373, discovery: "1952 Robinson" },
			Perfect {n: 16, p: "22202 × (22203-1)", digits: 1327, discovery: "1952 Robinson" },
			Perfect {n: 15, p: "21278 × (21279-1)", digits: 770, discovery: "1952 Robinson" },
			Perfect {n: 14, p: "2606 × (2607-1)", digits: 366, discovery: "1952 Robinson" },
			Perfect {n: 13, p: "2520 × (2521-1)", digits: 314, discovery: "1952 Robinson" },
			Perfect {n: 12, p: "2126 × (2127-1)", digits: 77, discovery: "1876 Lucas" },
			Perfect {n: 11, p: "2106 × (2107-1)", digits: 65, discovery: "1914 Powers" },
			Perfect {n: 10, p: "288 × (289-1)", digits: 54, discovery: "1911 Powers" },
			Perfect {n: 9, p: "260 × (261-1)", digits: 37, discovery: "1883 Pervushin" },
			Perfect {n: 8, p: "230 × (231-1)", digits: 19, discovery: "1772 Euler" },
			Perfect {n: 7, p: "218 × (219-1)", digits: 12, discovery: "1588 Cataldi" },
			Perfect {n: 6, p: "216 × (217-1)", digits: 10, discovery: "1588 Cataldi" },
			Perfect {n: 5, p: "212 × (213-1)", digits: 8, discovery: "1456 ?" },
			Perfect {n: 4, p: "26 × (27-1)", digits: 4, discovery: "?" },
			Perfect {n: 3, p: "24 × (25-1)", digits: 3, discovery: "?" },
			Perfect {n: 2, p: "22 × (23-1)", digits: 2, discovery: "?" },
			Perfect {n: 1, p: "21 × (23-1)", digits: 1, discovery: "?" },
		]
	}
}

pub fn render() -> seed::dom_types::Node<Msg> {
    let mut html = vec![];

    let perfects = perfects_utils::perfects();

    for n in 0..perfects.len() {
        let download_txt:String = vec!["https://static.bigprimes.net/archive/perfect/",&perfects[n].n.to_string(),".txt"].into_iter().collect();
        let download_zip:String = vec!["https://static.bigprimes.net/archive/perfect/",&perfects[n].n.to_string(),".zip"].into_iter().collect();
        html.push(
            tr![
                td![perfects[n].n.to_string()],//rank
                td![El::from_html(perfects[n].p)],//perfect number as a formula
                td![perfects[n].digits.to_string()],//digits in length
                td![perfects[n].discovery],//disocvery
                if perfects[n].n >= 25 {a![attrs!{At::Href => download_zip},"ZIP"]} else {a![attrs!{At::Href => download_txt},"TXT"]}//downloads
            ]
        );
    }

    div![
        h1!["The Perfect Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "perfecttable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}

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

    #[test]
    fn perfect_test<'a>() {
        let perfects:Vec<perfects_utils::Perfect<'a>> = perfects_utils::perfects();
        assert_eq!(perfects[0].digits, 46498850);
        assert_eq!(perfects[10].digits, 12640858);
    }
}<|endoftext|>


<commit_before>fn main() {
    while_loop(5);
}

fn infinite_loop() {
    loop {
        println!("Hello, world!");
    }
}

fn while_loop(x: i32) {
    let mut number = x;

    while number != 0 {
        println!("{}!", number);

        number = number - 1;
    }

    println!("Looping done!");
}<commit_msg>Example of looping over a collection with for loop<commit_after>fn main() {
    for_loop();
}

fn infinite_loop() {
    loop {
        println!("Hello, world!");
    }
}

fn while_loop(x: i32) {
    let mut number = x;

    while number != 0 {
        println!("{}!", number);

        number = number - 1;
    }

    println!("Looping done!");
}

fn for_loop() {
    let a = [10, 20, 30, 40, 50];

    for element in a.iter() {
        println!("{}!", element);
    }
}<|endoftext|>


<commit_before>//! Lettre is a mailer written in Rust. It provides a simple email builder and several transports.
//!
//! This mailer contains the available transports for your emails. To be sendable, the
//! emails have to implement `SendableEmail`.
//!

#![deny(missing_docs, unsafe_code, unstable_features, warnings)]

#[macro_use]
extern crate log;
extern crate base64;
#[cfg(feature = "crammd5-auth")]
extern crate hex;
#[cfg(feature = "crammd5-auth")]
extern crate crypto;
extern crate bufstream;
extern crate native_tls;
#[cfg(feature = "file-transport")]
extern crate serde_json;
#[cfg(feature = "serde-impls")]
extern crate serde;
#[cfg(feature = "serde-impls")]
#[macro_use]
extern crate serde_derive;

pub mod smtp;
pub mod sendmail;
pub mod stub;
#[cfg(feature = "file-transport")]
pub mod file;

#[cfg(feature = "file-transport")]
pub use file::FileEmailTransport;
pub use sendmail::SendmailTransport;
pub use smtp::{SmtpTransport, ClientSecurity};
pub use smtp::client::net::ClientTlsParameters;
use std::fmt::{self, Display, Formatter};
use std::io::Read;

/// Email address
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct EmailAddress(pub String);

impl Display for EmailAddress {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.write_str(&self.0)
    }
}

impl EmailAddress {
    /// Creates a new email address
    pub fn new(address: String) -> EmailAddress {
        EmailAddress(address)
    }
}

/// Email sendable by an SMTP client
pub trait SendableEmail<'a, T: Read + 'a> {
    /// To
    fn to(&self) -> Vec<EmailAddress>;
    /// From
    fn from(&self) -> EmailAddress;
    /// Message ID, used for logging
    fn message_id(&self) -> String;
    /// Message content
    fn message(&'a self) -> Box<T>;
}

/// Transport method for emails
pub trait EmailTransport<'a, U: Read + 'a, V> {
    /// Sends the email
    fn send<T: SendableEmail<'a, U> + 'a>(&mut self, email: &'a T) -> V;
}

/// Minimal email structure
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct SimpleSendableEmail {
    /// To
    to: Vec<EmailAddress>,
    /// From
    from: EmailAddress,
    /// Message ID
    message_id: String,
    /// Message content
    message: Vec<u8>,
}

impl SimpleSendableEmail {
    /// Returns a new email
    pub fn new(
        from_address: EmailAddress,
        to_addresses: Vec<EmailAddress>,
        message_id: String,
        message: String,
    ) -> SimpleSendableEmail {
        SimpleSendableEmail {
            from: from_address,
            to: to_addresses,
            message_id: message_id,
            message: message.into_bytes(),
        }
    }
}

impl<'a> SendableEmail<'a, &'a [u8]> for SimpleSendableEmail {
    fn to(&self) -> Vec<EmailAddress> {
        self.to.clone()
    }

    fn from(&self) -> EmailAddress {
        self.from.clone()
    }

    fn message_id(&self) -> String {
        self.message_id.clone()
    }

    fn message(&'a self) -> Box<&[u8]> {
        Box::new(self.message.as_slice())
    }
}
<commit_msg>fix(letter): Fix beta/nightly CI<commit_after>//! Lettre is a mailer written in Rust. It provides a simple email builder and several transports.
//!
//! This mailer contains the available transports for your emails. To be sendable, the
//! emails have to implement `SendableEmail`.
//!

#![deny(missing_docs, unsafe_code, unstable_features, warnings)]

#[macro_use]
extern crate log;
extern crate base64;
#[cfg(feature = "crammd5-auth")]
extern crate hex;
#[cfg(feature = "crammd5-auth")]
extern crate crypto;
extern crate bufstream;
extern crate native_tls;
#[cfg(feature = "file-transport")]
extern crate serde_json;
#[cfg(feature = "serde-impls")]
#[macro_use]
extern crate serde_derive;

pub mod smtp;
pub mod sendmail;
pub mod stub;
#[cfg(feature = "file-transport")]
pub mod file;

#[cfg(feature = "file-transport")]
pub use file::FileEmailTransport;
pub use sendmail::SendmailTransport;
pub use smtp::{SmtpTransport, ClientSecurity};
pub use smtp::client::net::ClientTlsParameters;
use std::fmt::{self, Display, Formatter};
use std::io::Read;

/// Email address
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct EmailAddress(pub String);

impl Display for EmailAddress {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.write_str(&self.0)
    }
}

impl EmailAddress {
    /// Creates a new email address
    pub fn new(address: String) -> EmailAddress {
        EmailAddress(address)
    }
}

/// Email sendable by an SMTP client
pub trait SendableEmail<'a, T: Read + 'a> {
    /// To
    fn to(&self) -> Vec<EmailAddress>;
    /// From
    fn from(&self) -> EmailAddress;
    /// Message ID, used for logging
    fn message_id(&self) -> String;
    /// Message content
    fn message(&'a self) -> Box<T>;
}

/// Transport method for emails
pub trait EmailTransport<'a, U: Read + 'a, V> {
    /// Sends the email
    fn send<T: SendableEmail<'a, U> + 'a>(&mut self, email: &'a T) -> V;
}

/// Minimal email structure
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct SimpleSendableEmail {
    /// To
    to: Vec<EmailAddress>,
    /// From
    from: EmailAddress,
    /// Message ID
    message_id: String,
    /// Message content
    message: Vec<u8>,
}

impl SimpleSendableEmail {
    /// Returns a new email
    pub fn new(
        from_address: EmailAddress,
        to_addresses: Vec<EmailAddress>,
        message_id: String,
        message: String,
    ) -> SimpleSendableEmail {
        SimpleSendableEmail {
            from: from_address,
            to: to_addresses,
            message_id: message_id,
            message: message.into_bytes(),
        }
    }
}

impl<'a> SendableEmail<'a, &'a [u8]> for SimpleSendableEmail {
    fn to(&self) -> Vec<EmailAddress> {
        self.to.clone()
    }

    fn from(&self) -> EmailAddress {
        self.from.clone()
    }

    fn message_id(&self) -> String {
        self.message_id.clone()
    }

    fn message(&'a self) -> Box<&[u8]> {
        Box::new(self.message.as_slice())
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use eutil::fptr_is_null;
use libc::{c_int};
use std::mem;
use string::{cef_string_userfree_utf8_alloc,cef_string_userfree_utf8_free,cef_string_utf8_set};
use types::{cef_string_list_t,cef_string_t};

//cef_string_list

#[no_mangle]
extern "C" fn cef_string_list_alloc() -> *mut cef_string_list_t {
    unsafe {
         let lt: Box<Vec<*mut cef_string_t>> = box vec!();
         mem::transmute(lt)
    }
}

#[no_mangle]
extern "C" fn cef_string_list_size(lt: *const cef_string_list_t) -> c_int {
    unsafe {
        if fptr_is_null(mem::transmute(lt)) { return 0; }
        let v: Box<Vec<*mut cef_string_t>> = mem::transmute(lt);
        v.len() as c_int
    }
}

#[no_mangle]
extern "C" fn cef_string_list_append(lt: *mut cef_string_list_t, value: *const cef_string_t) {
    unsafe {
        if fptr_is_null(mem::transmute(lt)) { return; }
        let mut v: Box<Vec<*mut cef_string_t>> = mem::transmute(lt);
        let cs = cef_string_userfree_utf8_alloc();
        cef_string_utf8_set(mem::transmute((*value).str), (*value).length, cs, 1);
        v.push(cs);
    }
}

#[no_mangle]
extern "C" fn cef_string_list_value(lt: *mut cef_string_list_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if index < 0 || fptr_is_null(mem::transmute(lt)) { return 0; }
        let v: Box<Vec<*mut cef_string_t>> = mem::transmute(lt);
        if index as uint > v.len() - 1 { return 0; }
        let cs = v.get(index as uint);
        cef_string_utf8_set(mem::transmute((**cs).str), (**cs).length, value, 1)
    }
}
<commit_msg>embedding: cef_string_list_clear()<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use eutil::fptr_is_null;
use libc::{c_int};
use std::mem;
use string::{cef_string_userfree_utf8_alloc,cef_string_userfree_utf8_free,cef_string_utf8_set};
use types::{cef_string_list_t,cef_string_t};

//cef_string_list

#[no_mangle]
extern "C" fn cef_string_list_alloc() -> *mut cef_string_list_t {
    unsafe {
         let lt: Box<Vec<*mut cef_string_t>> = box vec!();
         mem::transmute(lt)
    }
}

#[no_mangle]
extern "C" fn cef_string_list_size(lt: *const cef_string_list_t) -> c_int {
    unsafe {
        if fptr_is_null(mem::transmute(lt)) { return 0; }
        let v: Box<Vec<*mut cef_string_t>> = mem::transmute(lt);
        v.len() as c_int
    }
}

#[no_mangle]
extern "C" fn cef_string_list_append(lt: *mut cef_string_list_t, value: *const cef_string_t) {
    unsafe {
        if fptr_is_null(mem::transmute(lt)) { return; }
        let mut v: Box<Vec<*mut cef_string_t>> = mem::transmute(lt);
        let cs = cef_string_userfree_utf8_alloc();
        cef_string_utf8_set(mem::transmute((*value).str), (*value).length, cs, 1);
        v.push(cs);
    }
}

#[no_mangle]
extern "C" fn cef_string_list_value(lt: *mut cef_string_list_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if index < 0 || fptr_is_null(mem::transmute(lt)) { return 0; }
        let v: Box<Vec<*mut cef_string_t>> = mem::transmute(lt);
        if index as uint > v.len() - 1 { return 0; }
        let cs = v.get(index as uint);
        cef_string_utf8_set(mem::transmute((**cs).str), (**cs).length, value, 1)
    }
}

#[no_mangle]
extern "C" fn cef_string_list_clear(lt: *mut cef_string_list_t) {
    unsafe {
        if fptr_is_null(mem::transmute(lt)) { return; }
        let mut v: Box<Vec<*mut cef_string_t>> = mem::transmute(lt);
        if v.len() == 0 { return; }
        let mut cs;
        while v.len() != 0 {
            cs = v.pop();
            cef_string_userfree_utf8_free(cs.unwrap());
        }
    }
}
<|endoftext|>


<commit_before>#![feature(plugin, custom_attribute)]
#![plugin(gfx_macros)]

extern crate cgmath;
extern crate glutin;
extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_phase;
extern crate gfx_scene;

use gfx::traits::*;

#[vertex_format]
#[derive(Copy)]
struct Vertex {
    #[as_float]
    #[name = "a_Pos"]
    pos: [i8; 2],
}

impl Vertex {
    fn new(x: i8, y: i8) -> Vertex {
        Vertex {
            pos: [x, y],
        }
    }
}

#[shader_param]
#[derive(Clone)]
struct Params<R: gfx::Resources> {
    offset: [f32; 2],
    color: [f32; 4],
    _dummy: std::marker::PhantomData<R>,
}

static VERTEX_SRC: &'static [u8] = b"
    #version 120
    attribute vec2 a_Pos;
    uniform vec2 offset;
    void main() {
        vec2 pos = (a_Pos + offset)/10.0;
        gl_Position = vec4(pos, 0.0, 1.0);
    }
";

static FRAGMENT_SRC: &'static [u8] = b"
    #version 120
    uniform vec4 color;
    void main() {
        gl_FragColor = color;
    }
";

// Defining the technique, material, and entity

struct Technique<R: gfx::Resources> {
    program: gfx::ProgramHandle<R>,
    state: gfx::DrawState,
}

impl<R: gfx::Resources> Technique<R> {
    pub fn new<F: Factory<R>>(factory: &mut F) -> Technique<R> {
        let program = factory.link_program(VERTEX_SRC, FRAGMENT_SRC).unwrap();
        Technique {
            program: program,
            state: gfx::DrawState::new(),
        }
    }
}

struct Material;
impl gfx_phase::Material for Material {}

#[derive(Copy)]
struct ViewInfo(cgmath::Vector2<f32>);

impl gfx_phase::ToDepth for ViewInfo {
    type Depth = f32;
    fn to_depth(&self) -> f32 {0.0}
}

impl<R: gfx::Resources> gfx_phase::Technique<R, Material, ViewInfo>
for Technique<R> {
    type Kernel = ();
    type Params = Params<R>;

    fn test(&self, _: &gfx::Mesh<R>, _: &Material) -> Option<()> {
        Some(())
    }

    fn compile<'a>(&'a self, _: (), _: ViewInfo)
                   -> gfx_phase::TechResult<'a, R, Params<R>> {
        (   &self.program,
            Params {
                offset: [0.0; 2],
                color: [0.4, 0.5, 0.6, 0.0],
                _dummy: std::marker::PhantomData,
            },
            None,
            &self.state,
        )
    }

    fn fix_params(&self, _: &Material, space: &ViewInfo, params: &mut Params<R>) {
        use cgmath::FixedArray;
        params.offset = *space.0.as_fixed();
    }
}

//----------------------------------------

type Transform<S> = cgmath::Decomposed<S, cgmath::Vector3<S>, cgmath::Quaternion<S>>;

impl gfx_scene::ViewInfo<f32, Transform<f32>> for ViewInfo {
    fn new(_: cgmath::Matrix4<f32>, _: Transform<f32>, model: Transform<f32>) -> ViewInfo {
        ViewInfo(cgmath::Vector2::new(model.disp.x, model.disp.y))
    }
}

struct World {
    transforms: Vec<Transform<f32>>,
}

impl World {
    pub fn new() -> World {
        World {
            transforms: Vec::new(),
        }
    }
    pub fn add(&mut self, offset: cgmath::Vector2<f32>) -> u8 {
        let id = self.transforms.len();
        self.transforms.push(cgmath::Decomposed {
            scale: 1.0,
            rot: cgmath::Quaternion::identity(),
            disp: cgmath::vec3(offset.x, offset.y, 0.0),
        });
        id as u8
    }
}

impl gfx_scene::World for World {
    type Scalar = f32;
    type Rotation = cgmath::Quaternion<f32>;
    type Transform = Transform<f32>;
    type NodePtr = u8;
    type SkeletonPtr = ();
    type Iter = std::option::IntoIter<Transform<f32>>;

    fn get_transform(&self, node: &u8) -> &Transform<f32> {
        &self.transforms[*node as usize]
    }

    fn iter_bones(&self, _: &()) -> std::option::IntoIter<Transform<f32>> {
        None.into_iter()
    }
}

//----------------------------------------

fn main() {
    let window = glutin::WindowBuilder::new().with_vsync().build_strict().unwrap();
    window.set_title("Beta: gfx_scene example");
    unsafe { window.make_current() };
    let (w, h) = window.get_inner_size().unwrap();

    let frame = gfx::Frame::new(w as u16, h as u16);
    let mut device = gfx_device_gl::GlDevice::new(|s| window.get_proc_address(s));

    let vertex_data = [
        Vertex::new(0, 1),
        Vertex::new(0, 0),
        Vertex::new(1, 1),
        Vertex::new(1, 0),
    ];

    let mesh = device.create_mesh(&vertex_data);
    let slice = mesh.to_slice(gfx::PrimitiveType::TriangleStrip);

    let mut scene = gfx_scene::Scene::new(World::new());
    //scene.cull_frustum = false;
    let num = 10usize;
    let entities = (0..num).map(|i| {
        use std::num::Float;
        use cgmath::{Aabb3, Point3, vec2};
        let angle = (i as f32) / (num as f32) * std::f32::consts::PI * 2.0;
        let offset = vec2(4.0 * angle.cos(), 4.0 * angle.sin());
        gfx_scene::Entity {
            name: format!("entity-{}", i),
            material: Material,
            mesh: mesh.clone(),
            slice: slice.clone(),
            node: scene.world.add(offset),
            skeleton: None,
            bound: Aabb3::new(Point3::new(0f32, 0.0, 0.0), Point3::new(1.0, 1.0, 0.0)),
        }
    }).collect::<Vec<_>>();
    scene.entities.extend(entities.into_iter());

    //let mut harness = gfx_scene::PhaseHarness::<gfx_device_gl::GlDevice, _>::
    //    new(scene, device.create_renderer());

    let mut phase = gfx_phase::Phase::new_cached(
        "Main",
        Technique::new(&mut device),
    );
    phase.sort.push(gfx_phase::Sort::Program);
    //harness.phases.push(Box::new(phase));

    let clear_data = gfx::ClearData {
        color: [0.3, 0.3, 0.3, 1.0],
        depth: 1.0,
        stencil: 0,
    };
    //harness.clear = Some(clear_data);

    let camera = gfx_scene::Camera {
        name: "Cam".to_string(),
        projection: cgmath::Ortho {
            left: -10f32, right: 10f32,
            bottom: -10f32, top: 10f32,
            near: -1f32, far: 1f32,
        },
        //node: harness.scene.world.add(cgmath::Vector2::new(0.0, 0.0)),
        node: scene.world.add(cgmath::Vector2::new(0.0, 0.0))
    };

    'main: loop {
        use gfx_scene::AbstractScene;
        // quit when Esc is pressed.
        for event in window.poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) => break 'main,
                glutin::Event::Closed => break 'main,
                _ => {},
            }
        }

        //let buf = harness.draw(&camera, &frame).unwrap();
        let mut renderer = device.create_renderer();
        renderer.clear(clear_data, gfx::COLOR | gfx::DEPTH, &frame);
        scene.draw(&mut phase, &camera, &frame, &mut renderer).unwrap();
        device.submit(renderer.as_buffer());

        //device.submit(buf);
        window.swap_buffers();
        device.after_frame();
    }
}
<commit_msg>Made the projection scale into a constant<commit_after>#![feature(plugin, custom_attribute)]
#![plugin(gfx_macros)]

extern crate cgmath;
extern crate glutin;
extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_phase;
extern crate gfx_scene;

use gfx::traits::*;

static SCALE: f32 = 10.0;

#[vertex_format]
#[derive(Copy)]
struct Vertex {
    #[as_float]
    #[name = "a_Pos"]
    pos: [i8; 2],
}

impl Vertex {
    fn new(x: i8, y: i8) -> Vertex {
        Vertex {
            pos: [x, y],
        }
    }
}

#[shader_param]
#[derive(Clone)]
struct Params<R: gfx::Resources> {
    offset: [f32; 2],
    color: [f32; 4],
    scale: f32,
    _dummy: std::marker::PhantomData<R>,
}

static VERTEX_SRC: &'static [u8] = b"
    #version 120
    attribute vec2 a_Pos;
    uniform vec2 offset;
    uniform float scale;
    void main() {
        vec2 pos = (a_Pos + offset)/scale;
        gl_Position = vec4(pos, 0.0, 1.0);
    }
";

static FRAGMENT_SRC: &'static [u8] = b"
    #version 120
    uniform vec4 color;
    void main() {
        gl_FragColor = color;
    }
";

// Defining the technique, material, and entity

struct Technique<R: gfx::Resources> {
    program: gfx::ProgramHandle<R>,
    state: gfx::DrawState,
}

impl<R: gfx::Resources> Technique<R> {
    pub fn new<F: Factory<R>>(factory: &mut F) -> Technique<R> {
        let program = factory.link_program(VERTEX_SRC, FRAGMENT_SRC).unwrap();
        Technique {
            program: program,
            state: gfx::DrawState::new(),
        }
    }
}

struct Material;
impl gfx_phase::Material for Material {}

#[derive(Copy)]
struct ViewInfo(cgmath::Vector2<f32>);

impl gfx_phase::ToDepth for ViewInfo {
    type Depth = f32;
    fn to_depth(&self) -> f32 {0.0}
}

impl<R: gfx::Resources> gfx_phase::Technique<R, Material, ViewInfo>
for Technique<R> {
    type Kernel = ();
    type Params = Params<R>;

    fn test(&self, _: &gfx::Mesh<R>, _: &Material) -> Option<()> {
        Some(())
    }

    fn compile<'a>(&'a self, _: (), _: ViewInfo)
                   -> gfx_phase::TechResult<'a, R, Params<R>> {
        (   &self.program,
            Params {
                offset: [0.0; 2],
                color: [0.4, 0.5, 0.6, 0.0],
                scale: SCALE,
                _dummy: std::marker::PhantomData,
            },
            None,
            &self.state,
        )
    }

    fn fix_params(&self, _: &Material, space: &ViewInfo, params: &mut Params<R>) {
        use cgmath::FixedArray;
        params.offset = *space.0.as_fixed();
    }
}

//----------------------------------------

type Transform<S> = cgmath::Decomposed<S, cgmath::Vector3<S>, cgmath::Quaternion<S>>;

impl gfx_scene::ViewInfo<f32, Transform<f32>> for ViewInfo {
    fn new(_: cgmath::Matrix4<f32>, _: Transform<f32>, model: Transform<f32>) -> ViewInfo {
        ViewInfo(cgmath::Vector2::new(model.disp.x, model.disp.y))
    }
}

struct World {
    transforms: Vec<Transform<f32>>,
}

impl World {
    pub fn new() -> World {
        World {
            transforms: Vec::new(),
        }
    }
    pub fn add(&mut self, offset: cgmath::Vector2<f32>) -> u8 {
        let id = self.transforms.len();
        self.transforms.push(cgmath::Decomposed {
            scale: 1.0,
            rot: cgmath::Quaternion::identity(),
            disp: cgmath::vec3(offset.x, offset.y, 0.0),
        });
        id as u8
    }
}

impl gfx_scene::World for World {
    type Scalar = f32;
    type Rotation = cgmath::Quaternion<f32>;
    type Transform = Transform<f32>;
    type NodePtr = u8;
    type SkeletonPtr = ();
    type Iter = std::option::IntoIter<Transform<f32>>;

    fn get_transform(&self, node: &u8) -> &Transform<f32> {
        &self.transforms[*node as usize]
    }

    fn iter_bones(&self, _: &()) -> std::option::IntoIter<Transform<f32>> {
        None.into_iter()
    }
}

//----------------------------------------

fn main() {
    let window = glutin::WindowBuilder::new().with_vsync().build_strict().unwrap();
    window.set_title("Beta: gfx_scene example");
    unsafe { window.make_current() };
    let (w, h) = window.get_inner_size().unwrap();

    let frame = gfx::Frame::new(w as u16, h as u16);
    let mut device = gfx_device_gl::GlDevice::new(|s| window.get_proc_address(s));

    let vertex_data = [
        Vertex::new(0, 1),
        Vertex::new(0, 0),
        Vertex::new(1, 1),
        Vertex::new(1, 0),
    ];

    let mesh = device.create_mesh(&vertex_data);
    let slice = mesh.to_slice(gfx::PrimitiveType::TriangleStrip);

    let mut scene = gfx_scene::Scene::new(World::new());
    //scene.cull_frustum = false;
    let num = 10usize;
    let entities = (0..num).map(|i| {
        use std::num::Float;
        use cgmath::{Aabb3, Point3, vec2};
        let angle = (i as f32) / (num as f32) * std::f32::consts::PI * 2.0;
        let offset = vec2(4.0 * angle.cos(), 4.0 * angle.sin());
        gfx_scene::Entity {
            name: format!("entity-{}", i),
            material: Material,
            mesh: mesh.clone(),
            slice: slice.clone(),
            node: scene.world.add(offset),
            skeleton: None,
            bound: Aabb3::new(Point3::new(0f32, 0.0, 0.0), Point3::new(1.0, 1.0, 0.0)),
        }
    }).collect::<Vec<_>>();
    scene.entities.extend(entities.into_iter());

    //let mut harness = gfx_scene::PhaseHarness::<gfx_device_gl::GlDevice, _>::
    //    new(scene, device.create_renderer());

    let mut phase = gfx_phase::Phase::new_cached(
        "Main",
        Technique::new(&mut device),
    );
    phase.sort.push(gfx_phase::Sort::Program);
    //harness.phases.push(Box::new(phase));

    let clear_data = gfx::ClearData {
        color: [0.3, 0.3, 0.3, 1.0],
        depth: 1.0,
        stencil: 0,
    };
    //harness.clear = Some(clear_data);

    let camera = gfx_scene::Camera {
        name: "Cam".to_string(),
        projection: cgmath::Ortho {
            left: -SCALE, right: SCALE,
            bottom: -SCALE, top: SCALE,
            near: -1f32, far: 1f32,
        },
        //node: harness.scene.world.add(cgmath::Vector2::new(0.0, 0.0)),
        node: scene.world.add(cgmath::Vector2::new(0.0, 0.0))
    };

    'main: loop {
        use gfx_scene::AbstractScene;
        // quit when Esc is pressed.
        for event in window.poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) => break 'main,
                glutin::Event::Closed => break 'main,
                _ => {},
            }
        }

        //let buf = harness.draw(&camera, &frame).unwrap();
        let mut renderer = device.create_renderer();
        renderer.clear(clear_data, gfx::COLOR | gfx::DEPTH, &frame);
        scene.draw(&mut phase, &camera, &frame, &mut renderer).unwrap();
        device.submit(renderer.as_buffer());

        //device.submit(buf);
        window.swap_buffers();
        device.after_frame();
    }
}
<|endoftext|>


<commit_before>extern crate gimli;
extern crate getopts;
extern crate memmap;
extern crate object;

use object::Object;
use std::env;
use std::io;
use std::io::Write;
use std::fs;
use std::process;

#[derive(Default)]
struct Flags {
    info: bool,
    line: bool,
    aranges: bool,
}

fn print_usage(opts: &getopts::Options) -> ! {
    let brief = format!("Usage: {} <options> <file>", env::args().next().unwrap());
    write!(&mut io::stderr(), "{}", opts.usage(&brief)).ok();
    process::exit(1);
}

fn main() {
    let mut opts = getopts::Options::new();
    opts.optflag("i", "", "print .debug_info and .debug_types sections");
    opts.optflag("l", "", "print .debug_line section");
    opts.optflag("r", "", "print .debug_aranges section");

    let matches = match opts.parse(env::args().skip(1)) {
        Ok(m) => m,
        Err(e) => {
            writeln!(&mut io::stderr(), "{:?}\n", e).ok();
            print_usage(&opts);
        }
    };
    if matches.free.is_empty() {
        print_usage(&opts);
    }

    let mut all = true;
    let mut flags = Flags::default();
    if matches.opt_present("i") {
        flags.info = true;
        all = false;
    }
    if matches.opt_present("l") {
        flags.line = true;
        all = false;
    }
    if matches.opt_present("r") {
        flags.aranges = true;
        all = false;
    }
    if all {
        flags.info = true;
        flags.line = true;
        flags.aranges = true;
    }

    for file_path in &matches.free {
        if matches.free.len() != 1 {
            println!("{}", file_path);
            println!("");
        }

        let file = fs::File::open(&file_path).expect("Should open file");
        let file = memmap::Mmap::open(&file, memmap::Protection::Read)
            .expect("Should create a mmap for file");
        let file = object::File::parse(unsafe { file.as_slice() });

        if file.is_little_endian() {
            dump_file::<gimli::LittleEndian>(file, &flags);
        } else {
            dump_file::<gimli::BigEndian>(file, &flags);
        }
    }
}

fn dump_file<Endian>(file: object::File, flags: &Flags)
    where Endian: gimli::Endianity
{
    let debug_abbrev = file.get_section(".debug_abbrev").unwrap_or(&[]);
    let debug_abbrev = gimli::DebugAbbrev::<Endian>::new(debug_abbrev);
    let debug_str = file.get_section(".debug_str").unwrap_or(&[]);
    let debug_str = gimli::DebugStr::<Endian>::new(debug_str);

    if flags.info {
        dump_info(&file, debug_abbrev, debug_str);
        dump_types(&file, debug_abbrev, debug_str);
    }
    if flags.line {
        dump_line(&file, debug_abbrev);
    }
    if flags.aranges {
        dump_aranges::<Endian>(&file);
    }
}

fn dump_info<Endian>(file: &object::File,
                     debug_abbrev: gimli::DebugAbbrev<Endian>,
                     debug_str: gimli::DebugStr<Endian>)
    where Endian: gimli::Endianity
{
    if let Some(debug_info) = file.get_section(".debug_info") {
        println!(".debug_info");
        println!("");

        let debug_info = gimli::DebugInfo::<Endian>::new(&debug_info);

        let mut iter = debug_info.units();
        while let Some(unit) = iter.next().expect("Should parse compilation unit") {
            let abbrevs = unit.abbreviations(debug_abbrev)
                .expect("Error parsing abbreviations");

            dump_entries(unit.entries(&abbrevs), debug_str);
        }
    }
}

fn dump_types<Endian>(file: &object::File,
                      debug_abbrev: gimli::DebugAbbrev<Endian>,
                      debug_str: gimli::DebugStr<Endian>)
    where Endian: gimli::Endianity
{
    if let Some(debug_types) = file.get_section(".debug_types") {
        println!(".debug_types");
        println!("");

        let debug_types = gimli::DebugTypes::<Endian>::new(&debug_types);

        let mut iter = debug_types.units();
        while let Some(unit) = iter.next().expect("Should parse the unit OK") {
            let abbrevs = unit.abbreviations(debug_abbrev)
                .expect("Error parsing abbreviations");

            dump_entries(unit.entries(&abbrevs), debug_str);
        }
    }
}

fn dump_entries<Endian>(mut entries: gimli::EntriesCursor<Endian>,
                        debug_str: gimli::DebugStr<Endian>)
    where Endian: gimli::Endianity
{
    let mut depth = 0;
    while let Some((delta_depth, entry)) = entries.next_dfs().expect("Should parse next dfs") {
        depth += delta_depth;
        let indent = depth as usize * 2 + 2;
        println!("<{:2}><0x{:08x}>{:indent$}{}",
                 depth,
                 entry.offset(),
                 "",
                 entry.tag(),
                 indent = indent);

        let mut attrs = entry.attrs();
        while let Some(attr) = attrs.next().expect("Should parse attribute OK") {
            let mut value = attr.value();
            if let gimli::AttributeValue::DebugStrRef(o) = value {
                let s = debug_str.get_str(o).expect("Should have valid str offset");
                value = gimli::AttributeValue::String(s)
            }
            println!("{:indent$}{:28}{:?}",
                     "",
                     attr.name(),
                     value,
                     indent = indent + 18);
        }
    }
}

fn dump_line<Endian>(file: &object::File, debug_abbrev: gimli::DebugAbbrev<Endian>)
    where Endian: gimli::Endianity
{
    let debug_line = file.get_section(".debug_line");
    let debug_info = file.get_section(".debug_info");

    if let (Some(debug_line), Some(debug_info)) = (debug_line, debug_info) {
        println!(".debug_line");
        println!("");

        let debug_line = gimli::DebugLine::<Endian>::new(&debug_line);
        let debug_info = gimli::DebugInfo::<Endian>::new(&debug_info);

        let mut iter = debug_info.units();
        while let Some(unit) = iter.next().expect("Should parse unit header OK") {
            let abbrevs = unit.abbreviations(debug_abbrev)
                .expect("Error parsing abbreviations");

            let mut cursor = unit.entries(&abbrevs);
            cursor.next_dfs().expect("Should parse next dfs");

            let root = cursor.current().expect("Should have a root DIE");
            let offset = match root.attr_value(gimli::DW_AT_stmt_list) {
                Some(gimli::AttributeValue::DebugLineRef(offset)) => offset,
                _ => continue,
            };

            let header =
                gimli::LineNumberProgramHeader::new(debug_line, offset, unit.address_size());
            if let Ok(header) = header {
                println!("");
                println!("Offset:                             0x{:x}", offset.0);
                println!("Length:                             {}",
                         header.unit_length());
                println!("DWARF version:                      {}", header.version());
                println!("Prologue length:                    {}",
                         header.header_length());
                println!("Minimum instruction length:         {}",
                         header.minimum_instruction_length());
                println!("Maximum operations per instruction: {}",
                         header.maximum_operations_per_instruction());
                println!("Default is_stmt:                    {}",
                         header.default_is_stmt());
                println!("Line base:                          {}", header.line_base());
                println!("Line range:                         {}",
                         header.line_range());
                println!("Opcode base:                        {}",
                         header.opcode_base());

                println!("");
                println!("Opcodes:");
                for (i, length) in header.standard_opcode_lengths().iter().enumerate() {
                    println!("  Opcode {} as {} args", i + 1, length);
                }

                println!("");
                println!("The Directory Table:");
                for (i, dir) in header.include_directories().iter().enumerate() {
                    println!("  {} {}", i + 1, dir.to_string_lossy());
                }

                println!("");
                println!("The File Name Table");
                println!("  Entry\tDir\tTime\tSize\tName");
                for (i, file) in header.file_names().iter().enumerate() {
                    println!("  {}\t{}\t{}\t{}\t{}",
                             i + 1,
                             file.directory_index(),
                             file.last_modification(),
                             file.length(),
                             file.path_name().to_string_lossy());
                }

                println!("");
                println!("Line Number Statements:");
                let mut opcodes = header.opcodes();
                while let Some(opcode) = opcodes.next_opcode(&header)
                    .expect("Should parse opcode OK") {
                    println!("  {}", opcode);
                }

                println!("");
                println!("Line Number Rows:");
                println!("<pc>        [lno,col]");
                let mut state_machine = gimli::StateMachine::new(header);
                let mut file_index = 0;
                while let Some(row) = state_machine.next_row()
                    .expect("Should parse row OK") {
                    let line = row.line().unwrap_or(0);
                    let column = match row.column() {
                        gimli::ColumnType::Column(column) => column,
                        gimli::ColumnType::LeftEdge => 0,
                    };
                    print!("0x{:08x}  [{:4},{:2}]", row.address(), line, column);
                    if row.is_stmt() {
                        print!(" NS");
                    }
                    if row.basic_block() {
                        print!(" BB");
                    }
                    if row.end_sequence() {
                        print!(" ET");
                    }
                    if row.prologue_end() {
                        print!(" PE");
                    }
                    if row.epilogue_begin() {
                        print!(" EB");
                    }
                    if row.isa() != 0 {
                        print!(" IS={}", row.isa());
                    }
                    if row.discriminator() != 0 {
                        print!(" DI={}", row.discriminator());
                    }
                    if file_index != row.file_index() {
                        file_index = row.file_index();
                        if let Ok(file) = row.file() {
                            if let Some(directory) = file.directory(row.header()) {
                                print!(" uri: \"{}/{}\"",
                                       directory.to_string_lossy(),
                                       file.path_name().to_string_lossy());
                            } else {
                                print!(" uri: \"{}\"", file.path_name().to_string_lossy());
                            }
                        }
                    }
                    println!("");
                }
            }
        }
    }
}

fn dump_aranges<Endian>(file: &object::File)
    where Endian: gimli::Endianity
{
    let debug_aranges = file.get_section(".debug_aranges");
    let debug_info = file.get_section(".debug_info");

    if let (Some(debug_aranges), Some(debug_info)) = (debug_aranges, debug_info) {
        println!(".debug_aranges");
        println!("");

        let debug_aranges = gimli::DebugAranges::<Endian>::new(debug_aranges);
        let debug_info = gimli::DebugInfo::<Endian>::new(debug_info);

        let mut cu_die_offset = gimli::DebugInfoOffset(0);
        let mut prev_cu_offset = None;
        let mut aranges = debug_aranges.items();
        while let Some(arange) = aranges.next().expect("Should parse arange OK") {
            let cu_offset = arange.debug_info_offset();
            if Some(cu_offset) != prev_cu_offset {
                let cu = debug_info.header_from_offset(cu_offset)
                    .expect("Should parse unit header OK");
                cu_die_offset = gimli::DebugInfoOffset(cu_offset.0 + cu.header_size() as u64);
                prev_cu_offset = Some(cu_offset);
            }
            if let Some(segment) = arange.segment() {
                print!("arange starts at seg,off 0x{:08x},0x{:08x}, ",
                       segment,
                       arange.address());
            } else {
                print!("arange starts at 0x{:08x}, ", arange.address());
            }
            println!("length of 0x{:08x}, cu_die_offset = 0x{:08x}",
                     arange.length(),
                     cu_die_offset.0);
        }
    }
}
<commit_msg>dwarfdump: pretty print most attribute values<commit_after>extern crate gimli;
extern crate getopts;
extern crate memmap;
extern crate object;

use object::Object;
use std::env;
use std::io;
use std::io::Write;
use std::fs;
use std::process;

#[derive(Default)]
struct Flags {
    info: bool,
    line: bool,
    aranges: bool,
    raw: bool,
}

fn print_usage(opts: &getopts::Options) -> ! {
    let brief = format!("Usage: {} <options> <file>", env::args().next().unwrap());
    write!(&mut io::stderr(), "{}", opts.usage(&brief)).ok();
    process::exit(1);
}

fn main() {
    let mut opts = getopts::Options::new();
    opts.optflag("i", "", "print .debug_info and .debug_types sections");
    opts.optflag("l", "", "print .debug_line section");
    opts.optflag("r", "", "print .debug_aranges section");
    opts.optflag("", "raw", "print raw data values");

    let matches = match opts.parse(env::args().skip(1)) {
        Ok(m) => m,
        Err(e) => {
            writeln!(&mut io::stderr(), "{:?}\n", e).ok();
            print_usage(&opts);
        }
    };
    if matches.free.is_empty() {
        print_usage(&opts);
    }

    let mut all = true;
    let mut flags = Flags::default();
    if matches.opt_present("i") {
        flags.info = true;
        all = false;
    }
    if matches.opt_present("l") {
        flags.line = true;
        all = false;
    }
    if matches.opt_present("r") {
        flags.aranges = true;
        all = false;
    }
    if matches.opt_present("raw") {
        flags.raw = true;
    }
    if all {
        flags.info = true;
        flags.line = true;
        flags.aranges = true;
    }

    for file_path in &matches.free {
        if matches.free.len() != 1 {
            println!("{}", file_path);
            println!("");
        }

        let file = fs::File::open(&file_path).expect("Should open file");
        let file = memmap::Mmap::open(&file, memmap::Protection::Read)
            .expect("Should create a mmap for file");
        let file = object::File::parse(unsafe { file.as_slice() });

        if file.is_little_endian() {
            dump_file::<gimli::LittleEndian>(file, &flags);
        } else {
            dump_file::<gimli::BigEndian>(file, &flags);
        }
    }
}

fn dump_file<Endian>(file: object::File, flags: &Flags)
    where Endian: gimli::Endianity
{
    let debug_abbrev = file.get_section(".debug_abbrev").unwrap_or(&[]);
    let debug_abbrev = gimli::DebugAbbrev::<Endian>::new(debug_abbrev);
    let debug_str = file.get_section(".debug_str").unwrap_or(&[]);
    let debug_str = gimli::DebugStr::<Endian>::new(debug_str);

    if flags.info {
        dump_info(&file, debug_abbrev, debug_str, flags);
        dump_types(&file, debug_abbrev, debug_str, flags);
    }
    if flags.line {
        dump_line(&file, debug_abbrev);
    }
    if flags.aranges {
        dump_aranges::<Endian>(&file);
    }
}

fn dump_info<Endian>(file: &object::File,
                     debug_abbrev: gimli::DebugAbbrev<Endian>,
                     debug_str: gimli::DebugStr<Endian>,
                     flags: &Flags)
    where Endian: gimli::Endianity
{
    if let Some(debug_info) = file.get_section(".debug_info") {
        println!(".debug_info");
        println!("");

        let debug_info = gimli::DebugInfo::<Endian>::new(&debug_info);

        let mut iter = debug_info.units();
        while let Some(unit) = iter.next().expect("Should parse compilation unit") {
            let abbrevs = unit.abbreviations(debug_abbrev)
                .expect("Error parsing abbreviations");

            dump_entries(unit.entries(&abbrevs), debug_str, flags);
        }
    }
}

fn dump_types<Endian>(file: &object::File,
                      debug_abbrev: gimli::DebugAbbrev<Endian>,
                      debug_str: gimli::DebugStr<Endian>,
                      flags: &Flags)
    where Endian: gimli::Endianity
{
    if let Some(debug_types) = file.get_section(".debug_types") {
        println!(".debug_types");
        println!("");

        let debug_types = gimli::DebugTypes::<Endian>::new(&debug_types);

        let mut iter = debug_types.units();
        while let Some(unit) = iter.next().expect("Should parse the unit OK") {
            let abbrevs = unit.abbreviations(debug_abbrev)
                .expect("Error parsing abbreviations");

            dump_entries(unit.entries(&abbrevs), debug_str, flags);
        }
    }
}

fn dump_entries<Endian>(mut entries: gimli::EntriesCursor<Endian>,
                        debug_str: gimli::DebugStr<Endian>,
                        flags: &Flags)
    where Endian: gimli::Endianity
{
    let mut depth = 0;
    while let Some((delta_depth, entry)) = entries.next_dfs().expect("Should parse next dfs") {
        depth += delta_depth;
        let indent = depth as usize * 2 + 2;
        println!("<{:2}><0x{:08x}>{:indent$}{}",
                 depth,
                 entry.offset(),
                 "",
                 entry.tag(),
                 indent = indent);

        let mut attrs = entry.attrs();
        while let Some(attr) = attrs.next().expect("Should parse attribute OK") {
            print!("{:indent$}{:28}", "", attr.name(), indent = indent + 18);
            if flags.raw {
                println!("{:?}", attr.raw_value());
            } else {
                dump_attr_value(attr, debug_str);
            }
        }
    }
}

fn dump_attr_value<Endian>(attr: gimli::Attribute<Endian>, debug_str: gimli::DebugStr<Endian>)
    where Endian: gimli::Endianity
{
    let value = attr.value();
    match value {
        gimli::AttributeValue::Addr(address) => {
            println!("0x{:08x}", address);
        }
        gimli::AttributeValue::Sdata(data) => {
            println!("0x{:08x}", data);
        }
        gimli::AttributeValue::Udata(data) => {
            println!("0x{:08x}", data);
        }
        gimli::AttributeValue::Flag(true) => {
            println!("yes(1)");
        }
        gimli::AttributeValue::Flag(false) => {
            println!("no(0)");
        }
        gimli::AttributeValue::UnitRef(gimli::UnitOffset(offset)) => {
            println!("<0x{:08x}>", offset);
        }
        gimli::AttributeValue::DebugInfoRef(gimli::DebugInfoOffset(offset)) => {
            println!("0x{:08x}", offset);
        }
        gimli::AttributeValue::DebugLineRef(gimli::DebugLineOffset(offset)) => {
            println!("0x{:08x}", offset);
        }
        gimli::AttributeValue::DebugTypesRef(gimli::DebugTypesOffset(offset)) => {
            println!("0x{:08x}", offset);
        }
        gimli::AttributeValue::DebugStrRef(offset) => {
            if let Ok(s) = debug_str.get_str(offset) {
                println!("\"{}\"", s.to_string_lossy());
            } else {
                println!("{:?}", value);
            }
        }
        gimli::AttributeValue::String(s) => {
            println!("\"{}\"", s.to_string_lossy());
        }
        _ => println!("{:?}", value),
    }
}

fn dump_line<Endian>(file: &object::File, debug_abbrev: gimli::DebugAbbrev<Endian>)
    where Endian: gimli::Endianity
{
    let debug_line = file.get_section(".debug_line");
    let debug_info = file.get_section(".debug_info");

    if let (Some(debug_line), Some(debug_info)) = (debug_line, debug_info) {
        println!(".debug_line");
        println!("");

        let debug_line = gimli::DebugLine::<Endian>::new(&debug_line);
        let debug_info = gimli::DebugInfo::<Endian>::new(&debug_info);

        let mut iter = debug_info.units();
        while let Some(unit) = iter.next().expect("Should parse unit header OK") {
            let abbrevs = unit.abbreviations(debug_abbrev)
                .expect("Error parsing abbreviations");

            let mut cursor = unit.entries(&abbrevs);
            cursor.next_dfs().expect("Should parse next dfs");

            let root = cursor.current().expect("Should have a root DIE");
            let offset = match root.attr_value(gimli::DW_AT_stmt_list) {
                Some(gimli::AttributeValue::DebugLineRef(offset)) => offset,
                _ => continue,
            };

            let header =
                gimli::LineNumberProgramHeader::new(debug_line, offset, unit.address_size());
            if let Ok(header) = header {
                println!("");
                println!("Offset:                             0x{:x}", offset.0);
                println!("Length:                             {}",
                         header.unit_length());
                println!("DWARF version:                      {}", header.version());
                println!("Prologue length:                    {}",
                         header.header_length());
                println!("Minimum instruction length:         {}",
                         header.minimum_instruction_length());
                println!("Maximum operations per instruction: {}",
                         header.maximum_operations_per_instruction());
                println!("Default is_stmt:                    {}",
                         header.default_is_stmt());
                println!("Line base:                          {}", header.line_base());
                println!("Line range:                         {}",
                         header.line_range());
                println!("Opcode base:                        {}",
                         header.opcode_base());

                println!("");
                println!("Opcodes:");
                for (i, length) in header.standard_opcode_lengths().iter().enumerate() {
                    println!("  Opcode {} as {} args", i + 1, length);
                }

                println!("");
                println!("The Directory Table:");
                for (i, dir) in header.include_directories().iter().enumerate() {
                    println!("  {} {}", i + 1, dir.to_string_lossy());
                }

                println!("");
                println!("The File Name Table");
                println!("  Entry\tDir\tTime\tSize\tName");
                for (i, file) in header.file_names().iter().enumerate() {
                    println!("  {}\t{}\t{}\t{}\t{}",
                             i + 1,
                             file.directory_index(),
                             file.last_modification(),
                             file.length(),
                             file.path_name().to_string_lossy());
                }

                println!("");
                println!("Line Number Statements:");
                let mut opcodes = header.opcodes();
                while let Some(opcode) = opcodes.next_opcode(&header)
                    .expect("Should parse opcode OK") {
                    println!("  {}", opcode);
                }

                println!("");
                println!("Line Number Rows:");
                println!("<pc>        [lno,col]");
                let mut state_machine = gimli::StateMachine::new(header);
                let mut file_index = 0;
                while let Some(row) = state_machine.next_row()
                    .expect("Should parse row OK") {
                    let line = row.line().unwrap_or(0);
                    let column = match row.column() {
                        gimli::ColumnType::Column(column) => column,
                        gimli::ColumnType::LeftEdge => 0,
                    };
                    print!("0x{:08x}  [{:4},{:2}]", row.address(), line, column);
                    if row.is_stmt() {
                        print!(" NS");
                    }
                    if row.basic_block() {
                        print!(" BB");
                    }
                    if row.end_sequence() {
                        print!(" ET");
                    }
                    if row.prologue_end() {
                        print!(" PE");
                    }
                    if row.epilogue_begin() {
                        print!(" EB");
                    }
                    if row.isa() != 0 {
                        print!(" IS={}", row.isa());
                    }
                    if row.discriminator() != 0 {
                        print!(" DI={}", row.discriminator());
                    }
                    if file_index != row.file_index() {
                        file_index = row.file_index();
                        if let Ok(file) = row.file() {
                            if let Some(directory) = file.directory(row.header()) {
                                print!(" uri: \"{}/{}\"",
                                       directory.to_string_lossy(),
                                       file.path_name().to_string_lossy());
                            } else {
                                print!(" uri: \"{}\"", file.path_name().to_string_lossy());
                            }
                        }
                    }
                    println!("");
                }
            }
        }
    }
}

fn dump_aranges<Endian>(file: &object::File)
    where Endian: gimli::Endianity
{
    let debug_aranges = file.get_section(".debug_aranges");
    let debug_info = file.get_section(".debug_info");

    if let (Some(debug_aranges), Some(debug_info)) = (debug_aranges, debug_info) {
        println!(".debug_aranges");
        println!("");

        let debug_aranges = gimli::DebugAranges::<Endian>::new(debug_aranges);
        let debug_info = gimli::DebugInfo::<Endian>::new(debug_info);

        let mut cu_die_offset = gimli::DebugInfoOffset(0);
        let mut prev_cu_offset = None;
        let mut aranges = debug_aranges.items();
        while let Some(arange) = aranges.next().expect("Should parse arange OK") {
            let cu_offset = arange.debug_info_offset();
            if Some(cu_offset) != prev_cu_offset {
                let cu = debug_info.header_from_offset(cu_offset)
                    .expect("Should parse unit header OK");
                cu_die_offset = gimli::DebugInfoOffset(cu_offset.0 + cu.header_size() as u64);
                prev_cu_offset = Some(cu_offset);
            }
            if let Some(segment) = arange.segment() {
                print!("arange starts at seg,off 0x{:08x},0x{:08x}, ",
                       segment,
                       arange.address());
            } else {
                print!("arange starts at 0x{:08x}, ", arange.address());
            }
            println!("length of 0x{:08x}, cu_die_offset = 0x{:08x}",
                     arange.length(),
                     cu_die_offset.0);
        }
    }
}
<|endoftext|>


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

use std::any::Any;

use super::super::{Layout, PresentationLayout, ConcreteLayout};
use ::draw::{Drawable, BoundingBox, MeasureMode};
use ::platform::Context;
use ::paint::{Canvas, Point, MathRuler, Rect};
use ::props::{DisplayStyle, MathSize};

pub struct MmultiscriptLayout {
    pub(crate) base_layout: Box<Layout>,
    pub(crate) prescript_layout: Vec<(Box<Layout>, Box<Layout>)>,
    pub(crate) postscript_layout: Vec<(Box<Layout>, Box<Layout>)>,
    pub(crate) subscript_shift: f32,
    pub(crate) superscript_shift: f32,

    pub(crate) presentation_layout: PresentationLayout,
}

impl Layout for MmultiscriptLayout {
    fn layout<'a>(&'a self, context: &Context) -> Box<Drawable + 'a> {
        let mut wrapper = self.presentation_layout.layout(context);

        wrapper.wrap(MultiscriptDrawable {
            base: self.base_layout.layout(context),
            base_pos: Point::new(0f32, 0f32),
            prescripts: self.prescript_layout.iter().map(|&(ref superscript, ref subscript)| {
                MultiscriptDrawableChild {
                    subscript: subscript.layout(context),
                    subscript_pos: Point::new(0f32, 0f32),
                    superscript: superscript.layout(context),
                    superscript_pos: Point::new(0f32, 0f32),
                }
            }).collect(),
            postscripts: self.postscript_layout.iter().map(|&(ref superscript, ref subscript)| {
                MultiscriptDrawableChild {
                    subscript: subscript.layout(context),
                    subscript_pos: Point::new(0f32, 0f32),
                    superscript: superscript.layout(context),
                    superscript_pos: Point::new(0f32, 0f32),
                }
            }).collect(),
            superscript_shift: self.superscript_shift,
            subscript_shift: self.subscript_shift,
            display_style: self.presentation_layout.display_style,
            base_size: self.presentation_layout.script_level.get_font_size(context, &MathSize::NORMAL),
            bounding_box: BoundingBox::default(),
        });

        wrapper.calculate(context, &MeasureMode::Wrap, &MeasureMode::Wrap);

        Box::new(wrapper)
    }

    fn as_any(&self) -> &Any {
        self
    }

    fn as_any_mut(&mut self) -> &mut Any {
        self
    }
}

struct MultiscriptDrawable<'a> {
    base: Box<Drawable + 'a>,
    base_pos: Point,

    prescripts: Vec<MultiscriptDrawableChild<'a>>,
    postscripts: Vec<MultiscriptDrawableChild<'a>>,

    superscript_shift: f32,
    subscript_shift: f32,
    display_style: DisplayStyle,
    base_size: f32,

    bounding_box: BoundingBox,
}

struct MultiscriptDrawableChild<'a> {
    subscript: Box<Drawable + 'a>,
    subscript_pos: Point,
    superscript: Box<Drawable + 'a>,
    superscript_pos: Point,
}

struct ScriptPosition {
    base_baseline_pos: f32,
    superscript_baseline_pos: f32,
    subscript_baseline_pos: f32
}

impl ScriptPosition {
    fn max(&self, rhs: &ScriptPosition) -> ScriptPosition {
        ScriptPosition {
            base_baseline_pos: self.base_baseline_pos.max(rhs.base_baseline_pos),
            superscript_baseline_pos: self.superscript_baseline_pos.max(rhs.superscript_baseline_pos),
            subscript_baseline_pos: self.subscript_baseline_pos.max(rhs.subscript_baseline_pos),
        }
    }
}

impl<'a> MultiscriptDrawable<'a> {
    fn find_script_y_pos(&self, child: &MultiscriptDrawableChild<'a>, ruler: &MathRuler) -> ScriptPosition {

        let base = &self.base;
        let subscript = &child.subscript;
        let superscript = &child.superscript;

        let has_subscript = subscript.bounding_box().width() > 0f32 || subscript.bounding_box().height() > 0f32;
        let has_superscript = superscript.bounding_box().width() > 0f32 || superscript.bounding_box().height() > 0f32;

        // We will fix the position of superscript first
        let superscript_y_pos = 0f32;

        let base_y_pos = if has_superscript {
            // Recommended shift between baseline of base and baseline of superscript
            let superscript_shift = if self.superscript_shift.is_nan() {
                if self.display_style {
                    ruler.superscript_shift_up()
                } else {
                    ruler.superscript_shift_up_cramped()
                }
            } else {
                self.superscript_shift
            };

            let mut base_y_pos = superscript.bounding_box().baseline_pos() +
                superscript_shift -
                base.bounding_box().baseline_pos();

            // Minimum shift between superscript bottom and baseline of base
            let superscript_bottom_min = ruler.superscript_bottom_min();

            base_y_pos = base_y_pos.max(
                superscript.bounding_box().height() +
                    superscript_bottom_min -
                    base.bounding_box().baseline_pos()
            );

            // Maximum drop of baseline of superscript from top of base
            let superscript_baseline_drop_max = ruler.superscript_baseline_drop_max();

            base_y_pos = base_y_pos.max(
                superscript.bounding_box().baseline_pos() - superscript_baseline_drop_max
            );

            if has_subscript {
                // Maximum shift between superscript bottom and baseline of base when subscript is present
                let superscript_bottom_max_with_subscript = ruler.superscript_bottom_max_with_subscript();
                base_y_pos = base_y_pos.min(
                    superscript.bounding_box().height() +
                        superscript_bottom_max_with_subscript -
                        base.bounding_box().baseline_pos()
                );
            }

            base_y_pos
        } else {
            0f32
        };

        let subscript_y_pos = if has_subscript {
            // Recommended shift between baseline of base and baseline of subscript
            let subscript_shift = if self.subscript_shift.is_nan() {
                ruler.subscript_shift_down()
            } else {
                self.subscript_shift
            };

            let mut subscript_y_pos = base_y_pos + base.bounding_box().baseline_pos() +
                subscript_shift -
                subscript.bounding_box().baseline_pos();

            // Minimum shift between baseline of subscript and bottom of base
            let subscript_baseline_drop_min = ruler.subscript_baseline_drop_min();

            subscript_y_pos = subscript_y_pos.max(
                base_y_pos + base.bounding_box().height() +
                    subscript_baseline_drop_min -
                    subscript.bounding_box().baseline_pos()
            );

            // Maximum shift between top of subscript and baseline of base
            let subscript_top_max = ruler.subscript_top_max();

            subscript_y_pos = subscript_y_pos.max(
                base_y_pos +
                    base.bounding_box().baseline_pos() -
                    subscript_top_max
            );

            if has_superscript {
                // Minimum gap between bottom of superscript and top of subscript
                let sub_superscript_gap_min = ruler.sub_superscript_gap_min();

                subscript_y_pos.max(
                    superscript_y_pos +
                        superscript.bounding_box().height() +
                        sub_superscript_gap_min
                );
            }

            subscript_y_pos
        } else {
            base_y_pos + base.bounding_box().height()
        };

        return ScriptPosition {
            base_baseline_pos: base_y_pos + base.bounding_box().baseline_pos(),
            superscript_baseline_pos: superscript_y_pos + superscript.bounding_box().baseline_pos(),
            subscript_baseline_pos: subscript_y_pos + subscript.bounding_box().baseline_pos(),
        }
    }

    fn find_max_script_y_pos(&self, scripts: &Vec<MultiscriptDrawableChild<'a>>, ruler: &MathRuler) -> ScriptPosition {
        let mut script_pos = ScriptPosition {
            base_baseline_pos: 0.0,
            superscript_baseline_pos: 0.0,
            subscript_baseline_pos: 0.0,
        };

        for prescript in scripts.iter() {
            let current_script_pos =
                self.find_script_y_pos(prescript, ruler);

            script_pos = script_pos.max(&current_script_pos);
        }

        return script_pos;
    }

    fn draw_scripts(&self, scripts: &Vec<MultiscriptDrawableChild<'a>>, canvas: &Canvas, pen_pos: &Point) {
        for script in scripts.iter() {
            script.superscript.draw(canvas, &(pen_pos+&script.superscript_pos));
            script.subscript.draw(canvas, &(pen_pos+&script.subscript_pos));
        }
    }

    fn set_script_positions(scripts: &mut Vec<MultiscriptDrawableChild<'a>>,
                            script_pos: &ScriptPosition, current_pen_x: f32) -> Rect {
        let mut pen_x = current_pen_x;
        let mut y_max = 0f32;
        for script in scripts.iter_mut() {
            let width = script.subscript.bounding_box().width()
                .max(script.superscript.bounding_box().width());

            script.subscript_pos = Point::new(
                pen_x+width-script.subscript.bounding_box().width(),
                script_pos.subscript_baseline_pos-script.subscript.bounding_box().baseline_pos());

            script.superscript_pos = Point::new(
                pen_x+width-script.superscript.bounding_box().width(),
                script_pos.superscript_baseline_pos-script.superscript.bounding_box().baseline_pos());

            pen_x += width;
            y_max = y_max.max(script_pos.subscript_baseline_pos+script.subscript.bounding_box().baseline())
        }

        return Rect::new(pen_x-current_pen_x, y_max);
    }
}

impl<'a> Drawable for MultiscriptDrawable<'a> {
    fn draw(&self, canvas: &Canvas, pen_pos: &Point) {
        self.draw_scripts(&self.prescripts, canvas, pen_pos);
        self.base.draw(canvas, &(pen_pos+&self.base_pos));
        self.draw_scripts(&self.postscripts, canvas, pen_pos);
    }

    fn calculate(&mut self, context: &Context, width_mode: &MeasureMode, height_mode: &MeasureMode) {
        self.base.calculate(context, width_mode, height_mode);

        let ruler = context.platform().get_math_ruler(self.base_size);

        let script_pos = self.find_max_script_y_pos(&self.prescripts, ruler)
            .max(&self.find_max_script_y_pos(&self.postscripts, ruler));

        let subscript_baseline_pos = script_pos.subscript_baseline_pos;

        let base_baseline_pos = script_pos.base_baseline_pos
            .max(self.base.bounding_box().baseline_pos());

        let superscript_baseline_pos = script_pos.superscript_baseline_pos;

        let mut pen_x = 0f32;

        let prescript_bounds = MultiscriptDrawable::set_script_positions(
            &mut self.prescripts, &script_pos, pen_x);
        pen_x += prescript_bounds.width();

        self.base_pos = Point::new(pen_x, base_baseline_pos-self.base.bounding_box().baseline_pos());
        pen_x += self.base.bounding_box().width();

        let postscript_bounds = MultiscriptDrawable::set_script_positions(
            &mut self.postscripts, &script_pos, pen_x);
        pen_x += postscript_bounds.width();

        let height = prescript_bounds.height()
            .max(postscript_bounds.height())
            .max(self.base.bounding_box().height());

        self.bounding_box = BoundingBox::new(
            Rect::new(pen_x, height),
            height - (base_baseline_pos),
            height - (self.base.bounding_box().axis_pos() - self.base.bounding_box().baseline_pos() + base_baseline_pos),
        );
    }

    fn bounding_box(&self) -> &BoundingBox {
        &self.bounding_box
    }
}<commit_msg>Fix minimum gap between subscript and superscript not preserved<commit_after>/*
 * Copyright 2017 Sreejith Krishnan R
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

use std::any::Any;

use super::super::{Layout, PresentationLayout, ConcreteLayout};
use ::draw::{Drawable, BoundingBox, MeasureMode};
use ::platform::Context;
use ::paint::{Canvas, Point, MathRuler, Rect};
use ::props::{DisplayStyle, MathSize};

pub struct MmultiscriptLayout {
    pub(crate) base_layout: Box<Layout>,
    pub(crate) prescript_layout: Vec<(Box<Layout>, Box<Layout>)>,
    pub(crate) postscript_layout: Vec<(Box<Layout>, Box<Layout>)>,
    pub(crate) subscript_shift: f32,
    pub(crate) superscript_shift: f32,

    pub(crate) presentation_layout: PresentationLayout,
}

impl Layout for MmultiscriptLayout {
    fn layout<'a>(&'a self, context: &Context) -> Box<Drawable + 'a> {
        let mut wrapper = self.presentation_layout.layout(context);

        wrapper.wrap(MultiscriptDrawable {
            base: self.base_layout.layout(context),
            base_pos: Point::new(0f32, 0f32),
            prescripts: self.prescript_layout.iter().map(|&(ref superscript, ref subscript)| {
                MultiscriptDrawableChild {
                    subscript: subscript.layout(context),
                    subscript_pos: Point::new(0f32, 0f32),
                    superscript: superscript.layout(context),
                    superscript_pos: Point::new(0f32, 0f32),
                }
            }).collect(),
            postscripts: self.postscript_layout.iter().map(|&(ref superscript, ref subscript)| {
                MultiscriptDrawableChild {
                    subscript: subscript.layout(context),
                    subscript_pos: Point::new(0f32, 0f32),
                    superscript: superscript.layout(context),
                    superscript_pos: Point::new(0f32, 0f32),
                }
            }).collect(),
            superscript_shift: self.superscript_shift,
            subscript_shift: self.subscript_shift,
            display_style: self.presentation_layout.display_style,
            base_size: self.presentation_layout.script_level.get_font_size(context, &MathSize::NORMAL),
            bounding_box: BoundingBox::default(),
        });

        wrapper.calculate(context, &MeasureMode::Wrap, &MeasureMode::Wrap);

        Box::new(wrapper)
    }

    fn as_any(&self) -> &Any {
        self
    }

    fn as_any_mut(&mut self) -> &mut Any {
        self
    }
}

struct MultiscriptDrawable<'a> {
    base: Box<Drawable + 'a>,
    base_pos: Point,

    prescripts: Vec<MultiscriptDrawableChild<'a>>,
    postscripts: Vec<MultiscriptDrawableChild<'a>>,

    superscript_shift: f32,
    subscript_shift: f32,
    display_style: DisplayStyle,
    base_size: f32,

    bounding_box: BoundingBox,
}

struct MultiscriptDrawableChild<'a> {
    subscript: Box<Drawable + 'a>,
    subscript_pos: Point,
    superscript: Box<Drawable + 'a>,
    superscript_pos: Point,
}

struct ScriptPosition {
    base_baseline_pos: f32,
    superscript_baseline_pos: f32,
    subscript_baseline_pos: f32
}

impl ScriptPosition {
    fn max(&self, rhs: &ScriptPosition) -> ScriptPosition {
        ScriptPosition {
            base_baseline_pos: self.base_baseline_pos.max(rhs.base_baseline_pos),
            superscript_baseline_pos: self.superscript_baseline_pos.max(rhs.superscript_baseline_pos),
            subscript_baseline_pos: self.subscript_baseline_pos.max(rhs.subscript_baseline_pos),
        }
    }
}

impl<'a> MultiscriptDrawable<'a> {
    fn find_script_y_pos(&self, child: &MultiscriptDrawableChild<'a>, ruler: &MathRuler) -> ScriptPosition {

        let base = &self.base;
        let subscript = &child.subscript;
        let superscript = &child.superscript;

        let has_subscript = subscript.bounding_box().width() > 0f32 || subscript.bounding_box().height() > 0f32;
        let has_superscript = superscript.bounding_box().width() > 0f32 || superscript.bounding_box().height() > 0f32;

        // We will fix the position of superscript first
        let superscript_y_pos = 0f32;

        let base_y_pos = if has_superscript {
            // Recommended shift between baseline of base and baseline of superscript
            let superscript_shift = if self.superscript_shift.is_nan() {
                if self.display_style {
                    ruler.superscript_shift_up()
                } else {
                    ruler.superscript_shift_up_cramped()
                }
            } else {
                self.superscript_shift
            };

            let mut base_y_pos = superscript.bounding_box().baseline_pos() +
                superscript_shift -
                base.bounding_box().baseline_pos();

            // Minimum shift between superscript bottom and baseline of base
            let superscript_bottom_min = ruler.superscript_bottom_min();

            base_y_pos = base_y_pos.max(
                superscript.bounding_box().height() +
                    superscript_bottom_min -
                    base.bounding_box().baseline_pos()
            );

            // Maximum drop of baseline of superscript from top of base
            let superscript_baseline_drop_max = ruler.superscript_baseline_drop_max();

            base_y_pos = base_y_pos.max(
                superscript.bounding_box().baseline_pos() - superscript_baseline_drop_max
            );

            if has_subscript {
                // Maximum shift between superscript bottom and baseline of base when subscript is present
                let superscript_bottom_max_with_subscript = ruler.superscript_bottom_max_with_subscript();
                base_y_pos = base_y_pos.min(
                    superscript.bounding_box().height() +
                        superscript_bottom_max_with_subscript -
                        base.bounding_box().baseline_pos()
                );
            }

            base_y_pos
        } else {
            0f32
        };

        let subscript_y_pos = if has_subscript {
            // Recommended shift between baseline of base and baseline of subscript
            let subscript_shift = if self.subscript_shift.is_nan() {
                ruler.subscript_shift_down()
            } else {
                self.subscript_shift
            };

            let mut subscript_y_pos = base_y_pos + base.bounding_box().baseline_pos() +
                subscript_shift -
                subscript.bounding_box().baseline_pos();

            // Minimum shift between baseline of subscript and bottom of base
            let subscript_baseline_drop_min = ruler.subscript_baseline_drop_min();

            subscript_y_pos = subscript_y_pos.max(
                base_y_pos + base.bounding_box().height() +
                    subscript_baseline_drop_min -
                    subscript.bounding_box().baseline_pos()
            );

            // Maximum shift between top of subscript and baseline of base
            let subscript_top_max = ruler.subscript_top_max();

            subscript_y_pos = subscript_y_pos.max(
                base_y_pos +
                    base.bounding_box().baseline_pos() -
                    subscript_top_max
            );

            if has_superscript {
                // Minimum gap between bottom of superscript and top of subscript
                let sub_superscript_gap_min = ruler.sub_superscript_gap_min();

                subscript_y_pos = subscript_y_pos.max(
                    superscript_y_pos +
                        superscript.bounding_box().height() +
                        sub_superscript_gap_min
                );
            }

            subscript_y_pos
        } else {
            base_y_pos + base.bounding_box().height()
        };

        return ScriptPosition {
            base_baseline_pos: base_y_pos + base.bounding_box().baseline_pos(),
            superscript_baseline_pos: superscript_y_pos + superscript.bounding_box().baseline_pos(),
            subscript_baseline_pos: subscript_y_pos + subscript.bounding_box().baseline_pos(),
        }
    }

    fn find_max_script_y_pos(&self, scripts: &Vec<MultiscriptDrawableChild<'a>>, ruler: &MathRuler) -> ScriptPosition {
        let mut script_pos = ScriptPosition {
            base_baseline_pos: 0.0,
            superscript_baseline_pos: 0.0,
            subscript_baseline_pos: 0.0,
        };

        for prescript in scripts.iter() {
            let current_script_pos =
                self.find_script_y_pos(prescript, ruler);

            script_pos = script_pos.max(&current_script_pos);
        }

        return script_pos;
    }

    fn draw_scripts(&self, scripts: &Vec<MultiscriptDrawableChild<'a>>, canvas: &Canvas, pen_pos: &Point) {
        for script in scripts.iter() {
            script.superscript.draw(canvas, &(pen_pos+&script.superscript_pos));
            script.subscript.draw(canvas, &(pen_pos+&script.subscript_pos));
        }
    }

    fn set_script_positions(scripts: &mut Vec<MultiscriptDrawableChild<'a>>,
                            script_pos: &ScriptPosition, current_pen_x: f32) -> Rect {
        let mut pen_x = current_pen_x;
        let mut y_max = 0f32;
        for script in scripts.iter_mut() {
            let width = script.subscript.bounding_box().width()
                .max(script.superscript.bounding_box().width());

            script.subscript_pos = Point::new(
                pen_x+width-script.subscript.bounding_box().width(),
                script_pos.subscript_baseline_pos-script.subscript.bounding_box().baseline_pos());

            script.superscript_pos = Point::new(
                pen_x+width-script.superscript.bounding_box().width(),
                script_pos.superscript_baseline_pos-script.superscript.bounding_box().baseline_pos());

            pen_x += width;
            y_max = y_max.max(script_pos.subscript_baseline_pos+script.subscript.bounding_box().baseline())
        }

        return Rect::new(pen_x-current_pen_x, y_max);
    }
}

impl<'a> Drawable for MultiscriptDrawable<'a> {
    fn draw(&self, canvas: &Canvas, pen_pos: &Point) {
        self.draw_scripts(&self.prescripts, canvas, pen_pos);
        self.base.draw(canvas, &(pen_pos+&self.base_pos));
        self.draw_scripts(&self.postscripts, canvas, pen_pos);
    }

    fn calculate(&mut self, context: &Context, width_mode: &MeasureMode, height_mode: &MeasureMode) {
        self.base.calculate(context, width_mode, height_mode);

        let ruler = context.platform().get_math_ruler(self.base_size);

        let script_pos = self.find_max_script_y_pos(&self.prescripts, ruler)
            .max(&self.find_max_script_y_pos(&self.postscripts, ruler));

        let subscript_baseline_pos = script_pos.subscript_baseline_pos;

        let base_baseline_pos = script_pos.base_baseline_pos
            .max(self.base.bounding_box().baseline_pos());

        let superscript_baseline_pos = script_pos.superscript_baseline_pos;

        let mut pen_x = 0f32;

        let prescript_bounds = MultiscriptDrawable::set_script_positions(
            &mut self.prescripts, &script_pos, pen_x);
        pen_x += prescript_bounds.width();

        self.base_pos = Point::new(pen_x, base_baseline_pos-self.base.bounding_box().baseline_pos());
        pen_x += self.base.bounding_box().width();

        let postscript_bounds = MultiscriptDrawable::set_script_positions(
            &mut self.postscripts, &script_pos, pen_x);
        pen_x += postscript_bounds.width();

        let height = prescript_bounds.height()
            .max(postscript_bounds.height())
            .max(self.base.bounding_box().height());

        self.bounding_box = BoundingBox::new(
            Rect::new(pen_x, height),
            height - (base_baseline_pos),
            height - (self.base.bounding_box().axis_pos() - self.base.bounding_box().baseline_pos() + base_baseline_pos),
        );
    }

    fn bounding_box(&self) -> &BoundingBox {
        &self.bounding_box
    }
}<|endoftext|>