<commit_before>// extern crate libc;

// use libc::types;
use std::io::File;
use std::mem;
use std::os;

// https://stackoverflow.com/questions/24633784/is-there-a-gzip-library-available-for-rust

// #[link(name = "z")]
// extern {
//     fn gzopen(path: *const types::os::arch::c95::c_char,
//               mode: *const types::os::arch::c95::c_char)
//               -> types::common::c95::c_void;
// }

// #[link(name = "z")]
// extern {
//     fn gzread(file: types::common::c95::c_void,
//               buf:  types::common::c95::c_void,
//               len:  uint)
//               -> int;
// }

// #[link(name = "z")]
// extern {
//     fn gzclose(file: types::common::c95::c_void) -> int;
// }

fn pointer_size() -> uint {
    let tmp = 0u8;
    let boxed = box tmp;
    mem::size_of_val(&boxed)
}

fn main() {
    let args = os::args();
    if args.len() != 2 {
        println!("usage: read_blend_file /path/to/file.blend");
    } else {
        let slice: &str = args[1].as_slice();
        println!("open \"{}\" ...", slice);
        {
            // read 12 bytes from the Blender file
            let path = Path::new(slice);
            let display = path.display();
            let mut file = match File::open(&path) {
                Err(why) => fail!("couldn't open {}: {}", display, why.desc),
                Ok(file) => file,
            };
            let mut buf = [0u8, ..12];
            match file.read(buf) {
                Err(why) => fail!("couldn't open {}: {}", display, why.desc),
                Ok(_) => (),
            }
            // pack those 12 bytes into a string ...
            let mut header = String::new();
            for n in range(0u, 12) {
                header.push(buf[n] as char);
            }
            // ... to be able to compare them
            let slice = header.as_slice();
            let blender: &str = slice.slice(0, 7); // first 7 chars
            if blender == "BLENDER" {
                println!("INFO: a Blender file.");
                let ptr_size = pointer_size();
                println!("size of pointer in bytes: {}", ptr_size);
                println!("Header (12 chars): {}", header);
                let mut ptr_size_differs = false;
                if buf[7] as char == '_' {
                    // 32-bit pointers expected
                    if ptr_size != 4 {
                        ptr_size_differs = true;
                    }
                    println!("32-bit pointers in file, pointer size differs? {}", ptr_size_differs);
                } else {
                    // 64-bit pointers expected
                    if ptr_size != 8 {
                        ptr_size_differs = true;
                    }
                    println!("64-bit pointers in file, pointer size differs? {}", ptr_size_differs);
                }
                // little endian or big endian?
                let mut l_endian;
                let endian_test = 1u16; // value one stored in two bytes
                if endian_test.to_le() != endian_test {
                    l_endian = false;
                } else {
                    // if we are on a little endian machine to_le() is a no-op
                    l_endian = true;
                }
                println!("l_endian = {}", l_endian);
                let mut switch_endian;
                if buf[8] as char == 'v' {
                    // file stores little endian
                    if !l_endian {
                        switch_endian = true;
                    } else {
                        switch_endian = false;
                    }
                } else {
                    // file stores big endian
                    if l_endian {
                        switch_endian = true;
                    } else {
                        switch_endian = false;
                    }
                }
                println!("switch_endian = {}", switch_endian);
                // get the version number
                let mut num = String::new();
                for n in range(9u, 12) {
                    num.push(buf[n] as char);
                }
                println!("num = {}", num);
                // assumes 64-bit pointers (in file as well as on platform)
                loop {
                    // read_file_dna
                    let mut bhead8 = [0u8, ..24]; // 4 * int + 64-bit pointer
                    match file.read(bhead8) {
                        Err(why) => fail!("couldn't open {}: {}", display, why.desc),
                        Ok(_) => (),
                    }
                    // pack those 12 bytes into a string ...
                    let mut bhead = String::new();
                    for n in range(0u, 24) {
                        bhead.push(bhead8[n] as char);
                    }
                    let slice = bhead.as_slice();
                    let code: &str = slice.slice(0, 4); // first 4 chars
                    println!("code = {}", code);
                    let mut len: uint = 0;
                    println!("bhead8[4] = {}", bhead8[4] as uint);
                    println!("bhead8[5] = {}", bhead8[5] as uint);
                    println!("bhead8[6] = {}", bhead8[6] as uint);
                    println!("bhead8[7] = {}", bhead8[7] as uint);
                    len += (bhead8[4] as uint) <<  0;
                    len += (bhead8[5] as uint) <<  8;
                    len += (bhead8[6] as uint) << 16;
                    len += (bhead8[7] as uint) << 24;
                    println!("len = {}", len);
                    file.read_exact(len);
                }
            } else {
                println!("ERROR: not a Blender file.");
            }
        } // file gets closed here
    }
}
<commit_msg>Be less verbose and detect the end of the file (checking code and len).<commit_after>// extern crate libc;

// use libc::types;
use std::io::File;
use std::mem;
use std::os;

// https://stackoverflow.com/questions/24633784/is-there-a-gzip-library-available-for-rust

// #[link(name = "z")]
// extern {
//     fn gzopen(path: *const types::os::arch::c95::c_char,
//               mode: *const types::os::arch::c95::c_char)
//               -> types::common::c95::c_void;
// }

// #[link(name = "z")]
// extern {
//     fn gzread(file: types::common::c95::c_void,
//               buf:  types::common::c95::c_void,
//               len:  uint)
//               -> int;
// }

// #[link(name = "z")]
// extern {
//     fn gzclose(file: types::common::c95::c_void) -> int;
// }

fn pointer_size() -> uint {
    let tmp = 0u8;
    let boxed = box tmp;
    mem::size_of_val(&boxed)
}

fn main() {
    let args = os::args();
    if args.len() != 2 {
        println!("usage: read_blend_file /path/to/file.blend");
    } else {
        let slice: &str = args[1].as_slice();
        println!("open \"{}\" ...", slice);
        {
            // read 12 bytes from the Blender file
            let path = Path::new(slice);
            let display = path.display();
            let mut file = match File::open(&path) {
                Err(why) => fail!("couldn't open {}: {}", display, why.desc),
                Ok(file) => file,
            };
            let mut buf = [0u8, ..12];
            match file.read(buf) {
                Err(why) => fail!("couldn't open {}: {}", display, why.desc),
                Ok(_) => (),
            }
            // pack those 12 bytes into a string ...
            let mut header = String::new();
            for n in range(0u, 12) {
                header.push(buf[n] as char);
            }
            // ... to be able to compare them
            let slice = header.as_slice();
            let blender: &str = slice.slice(0, 7); // first 7 chars
            if blender == "BLENDER" {
                println!("INFO: a Blender file.");
                let ptr_size = pointer_size();
                println!("size of pointer in bytes: {}", ptr_size);
                println!("Header (12 chars): {}", header);
                let mut ptr_size_differs = false;
                if buf[7] as char == '_' {
                    // 32-bit pointers expected
                    if ptr_size != 4 {
                        ptr_size_differs = true;
                    }
                    println!("32-bit pointers in file, pointer size differs? {}", ptr_size_differs);
                } else {
                    // 64-bit pointers expected
                    if ptr_size != 8 {
                        ptr_size_differs = true;
                    }
                    println!("64-bit pointers in file, pointer size differs? {}", ptr_size_differs);
                }
                // little endian or big endian?
                let mut l_endian;
                let endian_test = 1u16; // value one stored in two bytes
                if endian_test.to_le() != endian_test {
                    l_endian = false;
                } else {
                    // if we are on a little endian machine to_le() is a no-op
                    l_endian = true;
                }
                println!("l_endian = {}", l_endian);
                let mut switch_endian;
                if buf[8] as char == 'v' {
                    // file stores little endian
                    if !l_endian {
                        switch_endian = true;
                    } else {
                        switch_endian = false;
                    }
                } else {
                    // file stores big endian
                    if l_endian {
                        switch_endian = true;
                    } else {
                        switch_endian = false;
                    }
                }
                println!("switch_endian = {}", switch_endian);
                // get the version number
                let mut num = String::new();
                for n in range(9u, 12) {
                    num.push(buf[n] as char);
                }
                println!("num = {}", num);
                // assumes 64-bit pointers (in file as well as on platform)
                loop {
                    // read_file_dna
                    let mut bhead8 = [0u8, ..24]; // 4 * int + 64-bit pointer
                    match file.read(bhead8) {
                        Err(why) => fail!("couldn't open {}: {}", display, why.desc),
                        Ok(_) => (),
                    }
                    // pack those 12 bytes into a string ...
                    let mut bhead = String::new();
                    for n in range(0u, 24) {
                        bhead.push(bhead8[n] as char);
                    }
                    let slice = bhead.as_slice();
                    let code: &str = slice.slice(0, 4); // first 4 chars
                    println!("code = {}", code);
                    let mut len: uint = 0;
                    len += (bhead8[4] as uint) <<  0;
                    len += (bhead8[5] as uint) <<  8;
                    len += (bhead8[6] as uint) << 16;
                    len += (bhead8[7] as uint) << 24;
                    println!("len = {}", len);
                    file.read_exact(len);
                    if code == "ENDB" && len == 0 {
                        break;
                    }
                }
            } else {
                println!("ERROR: not a Blender file.");
            }
        } // file gets closed here
    }
}
<|endoftext|>


<commit_before>use chrono::{DateTime, Utc};

#[allow(non_snake_case)]
#[derive(Debug, Default, PartialEq, Serialize, FromXmlStream)]
pub struct ShippingAddress {
  pub StateOrRegion: String,
  pub City: String,
  pub CountryCode: String,
  pub PostalCode: String,
  pub Name: String,
  pub AddressLine1: String,
  pub AddressLine2: String,
  pub Phone: Option<String>,
}

#[allow(non_snake_case)]
#[derive(Debug, Default, PartialEq, Serialize, FromXmlStream)]
pub struct CurrencyAmount {
  pub CurrencyCode: String,
  pub Amount: String,
}

#[allow(non_snake_case)]
#[derive(Debug, Default, PartialEq, Serialize, FromXmlStream)]
pub struct Order {
  /// An Amazon-defined order identifier, in 3-7-7 format.
  pub AmazonOrderId: String,
  /// A seller-defined order identifier.
  pub SellerOrderId: String,
  /// The date when the order was created.
  pub PurchaseDate: Option<DateTime<Utc>>,
  /// The date when the order was last updated.
  pub LastUpdateDate: Option<DateTime<Utc>>,
  /// The current order status.
  pub OrderStatus: OrderStatus,
  /// How the order was fulfilled: by Amazon (AFN) or by the seller (MFN).
  pub FulfillmentChannel: FulfillmentChannel,
  /// The sales channel of the first item in the order.
  pub SalesChannel: String,
  /// The order channel of the first item in the order.
  pub OrderChannel: String,
  /// The shipment service level of the order.
  pub ShipServiceLevel: String,
  /// The shipping address for the order.
  pub ShippingAddress: Option<ShippingAddress>,
  /// The total charge for the order.
  pub OrderTotal: Option<CurrencyAmount>,
  /// The number of items shipped.
  pub NumberOfItemsShipped: i32,
  /// The number of items unshipped.
  pub NumberOfItemsUnshipped: i32,

  // pub PaymentExecutionDetail: ?
  /// The payment method for the order.
  /// This response element is limited to Cash On Delivery (COD)
  /// and Convenience Store (CVS) payment methods.
  /// Unless you need the specific COD payment information provided
  /// by the PaymentExecutionDetailItem element, we recommend using
  /// the PaymentMethodDetails response element to get payment
  /// method information.
  pub PaymentMethod: PaymentMethod,

  // pub PaymentMethodDetails: ?
  /// true if this is a replacement order.
  pub IsReplacementOrder: bool,
  /// The AmazonOrderId value for the order that is being replaced.
  pub ReplacedOrderId: String,
  /// The anonymized identifier for the Marketplace where the order was placed.
  pub MarketplaceId: String,
  /// The anonymized e-mail address of the buyer.
  pub BuyerEmail: String,
  /// The name of the buyer.
  pub BuyerName: String,
  /// The county of the buyer.
  /// This element is used only in the Brazil marketplace.
  pub BuyerCounty: String,

  // pub BuyerTaxInfo: ?
  /// The shipment service level category of the order.
  /// ShipmentServiceLevelCategory values: Expedited, FreeEconomy, NextDay, SameDay, SecondDay, Scheduled, Standard
  pub ShipmentServiceLevelCategory: String,
  /// true if the order was shipped by the Amazon Transportation for Merchants (Amazon TFM) service.
  /// Amazon TFM is available only in the China marketplace.
  pub ShippedByAmazonTFM: bool,
  /// The status of the Amazon TFM order. Returned only if
  /// ShippedByAmazonTFM = True. Note that even if ShippedByAmazonTFM = True,
  /// TFMShipmentStatus will not be returned if you have
  /// not yet created the shipment.
  /// TFMShipmentStatus values: PendingPickUp, LabelCanceled, PickedUp,
  /// AtDestinationFC, Delivered, RejectedByBuyer, Undeliverable,
  /// ReturnedToSeller
  /// Amazon TFM is available only in the China marketplace.
  pub TFMShipmentStatus: String,
  /// The status of the Amazon Easy Ship order.
  /// This element is included only for Amazon Easy Ship orders.
  /// EasyShipShipmentStatus values: PendingPickUp, LabelCanceled,
  /// PickedUp, OutForDelivery, Damaged, Delivered, RejectedByBuyer,
  /// Undeliverable, ReturnedToSeller
  /// Amazon Easy Ship is available only in the India marketplace.
  pub EasyShipShipmentStatus: String,
  /// The type of the order.
  pub OrderType: String,
  /// The start of the time period that you have committed to
  /// ship the order. In ISO 8601 date time format.
  pub EarliestShipDate: Option<DateTime<Utc>>,
  /// The end of the time period that you have committed to ship
  /// the order. In ISO 8601 date time format.
  pub LatestShipDate: Option<DateTime<Utc>>,
  /// The start of the time period that you have commited to fulfill
  /// the order. In ISO 8601 date time format.
  pub EarliestDeliveryDate: Option<DateTime<Utc>>,
  /// The end of the time period that you have commited to fulfill the order.
  /// In ISO 8601 date time format.
  pub LatestDeliveryDate: Option<DateTime<Utc>>,
  /// true if the order is an Amazon Business order.
  /// An Amazon Business order is an order where the buyer is a
  /// Verified Business Buyer and the seller is an Amazon Business Seller.
  /// For more information about the Amazon Business Seller Program,
  /// see the Amazon Business website.
  pub IsBusinessOrder: bool,
  /// The purchase order (PO) number entered by the buyer at checkout.
  pub PurchaseOrderNumber: String,
  /// true if the order is a seller-fulfilled Amazon Prime order.
  pub IsPrime: bool,
  /// true if the order has a Premium Shipping Service Level Agreement.
  /// For more information about Premium Shipping orders,
  /// see "Premium Shipping Options" in the Seller Central Help for
  /// your marketplace.
  pub IsPremiumOrder: bool,
  /// Indicates the date by which the seller must respond to the buyer
  /// with an Estimated Ship Date.
  pub PromiseResponseDueDate: Option<DateTime<Utc>>,
  /// true if the Estimated Ship Date is set for the order.
  pub IsEstimatedShipDateSet: bool,
}

str_enum! {
  /// A list of OrderStatus values. Used to select orders with a current status that matches
  /// one of the status values that you specify.
  ///
  /// Unshipped and PartiallyShipped must be used together in this version of the Orders API
  /// section. Using one and not the other returns an error.
  ///
  /// [Reference](http://docs.developer.amazonservices.com/en_CA/orders-2013-09-01/Orders_ListOrders.html)
  pub enum OrderStatus {
    PendingAvailability,
    Pending,
    Unshipped,
    PartiallyShipped,
    Shipped,
    InvoiceUnconfirmed,
    Canceled,
    Unfulfillable,
  }
}

str_enum! {
  ///	A list that indicates how an order was fulfilled.
  ///
  /// [Reference](http://docs.developer.amazonservices.com/en_CA/orders-2013-09-01/Orders_ListOrders.html)
  pub enum FulfillmentChannel {
    AFN,
    MFN,
  }
}

str_enum! {
  /// A list of PaymentMethod values. Used to select orders paid for with the payment methods
  /// that you specify.
  ///
  /// Note: COD and CVS values are valid only in Japan (JP).
  pub enum PaymentMethod {
    COD,
    CVS,
    Other,
  }
}

str_enum! {
  /// A list of TFMShipmentStatus values. Used to select Amazon Transportation for Merchants (TFM)
  /// orders with a current status that matches one of the status values that you specify.
  /// If TFMShipmentStatus is specified, only TFM orders are returned.
  ///
  /// Note: The TFMShipmentStatus request parameter is available only in China (CN).
  pub enum TFMShipmentStatus {
    PendingPickUp,
    LabelCanceled,
    PickedUp,
    AtDestinationFC,
    Delivered,
    RejectedByBuyer,
    Undeliverable,
    ReturnedToSeller,
    Lost,
  }
}

#[allow(non_snake_case)]
#[derive(Debug, Default, PartialEq, Serialize, FromXmlStream)]
pub struct OrderItem {
  pub OrderItemId: String,
  pub QuantityOrdered: i32,
  pub Title: String,
  pub ASIN: String,
  pub SellerSKU: String,
  pub QuantityShipped: i32,
  pub ItemPrice: Option<CurrencyAmount>,
  pub ItemTax: Option<CurrencyAmount>,
  pub GiftWrapPrice: Option<CurrencyAmount>,
  pub GiftWrapTax: Option<CurrencyAmount>,
  pub PromotionDiscount: Option<CurrencyAmount>,
  pub ShippingPrice: Option<CurrencyAmount>,
  pub ShippingDiscount: Option<CurrencyAmount>,
  pub ShippingTax: Option<CurrencyAmount>,
}

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

  #[test]
  fn test_decode_order() {
    test_decode!(
      Order,
      r#"
        <LatestShipDate>2018-12-18T07:59:59Z</LatestShipDate>
        <OrderType>StandardOrder</OrderType>
        <SellerOrderId>666</SellerOrderId>
        <PurchaseDate>2018-12-16T18:53:45.856Z</PurchaseDate>
        <AmazonOrderId>111-3081581-6666666</AmazonOrderId>
        <BuyerEmail>666@marketplace.amazon.com</BuyerEmail>
        <IsReplacementOrder>false</IsReplacementOrder>
        <LastUpdateDate>2018-12-17T16:50:11.820Z</LastUpdateDate>
        <NumberOfItemsShipped>1</NumberOfItemsShipped>
        <ShipServiceLevel>Std US D2D Dom</ShipServiceLevel>
        <OrderStatus>Shipped</OrderStatus>
        <SalesChannel>Amazon.com</SalesChannel>
        <ShippedByAmazonTFM>false</ShippedByAmazonTFM>
        <IsBusinessOrder>false</IsBusinessOrder>
        <LatestDeliveryDate>2018-12-27T07:59:59Z</LatestDeliveryDate>
        <NumberOfItemsUnshipped>0</NumberOfItemsUnshipped>
        <PaymentMethodDetails>
          <PaymentMethodDetail>Standard</PaymentMethodDetail>
        </PaymentMethodDetails>
        <BuyerName>First Last</BuyerName>
        <EarliestDeliveryDate>2018-12-20T08:00:00Z</EarliestDeliveryDate>
        <OrderTotal>
          <CurrencyCode>USD</CurrencyCode>
          <Amount>666.66</Amount>
        </OrderTotal>
        <IsPremiumOrder>false</IsPremiumOrder>
        <EarliestShipDate>2018-12-17T08:00:00Z</EarliestShipDate>
        <MarketplaceId>ATVPDKIKX0DER</MarketplaceId>
        <FulfillmentChannel>MFN</FulfillmentChannel>
        <PaymentMethod>Other</PaymentMethod>
        <ShippingAddress>
          <City>SAN MATEO</City>
          <AddressType>Residential</AddressType>
          <PostalCode>92683-4617</PostalCode>
          <isAddressSharingConfidential>false</isAddressSharingConfidential>
          <StateOrRegion>CA</StateOrRegion>
          <CountryCode>US</CountryCode>
          <Name>First Last</Name>
          <AddressLine1>8888 J AVE</AddressLine1>
        </ShippingAddress>
        <IsPrime>true</IsPrime>
        <ShipmentServiceLevelCategory>Standard</ShipmentServiceLevelCategory>"#,
      Order {
        LatestShipDate: Some(
          "2018-12-18T07:59:59Z"
            .parse()
            .expect("parse LatestShipDate",)
        ),
        OrderType: "StandardOrder".to_string(),
        PurchaseDate: Some(
          "2018-12-16T18:53:45.856Z"
            .parse()
            .expect("parse PurchaseDate")
        ),
        AmazonOrderId: "111-3081581-6666666".to_string(),
        LastUpdateDate: Some(
          "2018-12-17T16:50:11.820Z"
            .parse()
            .expect("parse LastUpdateDate",)
        ),
        ShipServiceLevel: "Std US D2D Dom".to_string(),
        NumberOfItemsShipped: 1,
        OrderStatus: OrderStatus::Shipped,
        SalesChannel: "Amazon.com".to_string(),
        IsBusinessOrder: false,
        NumberOfItemsUnshipped: 0,
        IsPremiumOrder: false,
        EarliestShipDate: Some(
          "2018-12-17T08:00:00Z"
            .parse()
            .expect("parse EarliestShipDate",)
        ),
        MarketplaceId: "ATVPDKIKX0DER".to_string(),
        FulfillmentChannel: FulfillmentChannel::MFN,
        PaymentMethod: PaymentMethod::Other,
        IsPrime: true,
        ShipmentServiceLevelCategory: "Standard".to_string(),
        SellerOrderId: "666".to_string(),
        BuyerEmail: "666@marketplace.amazon.com".to_string(),
        BuyerName: "First Last".to_string(),
        OrderTotal: Some(CurrencyAmount {
          CurrencyCode: "USD".to_string(),
          Amount: "666.66".to_owned(),
        }),
        ShippingAddress: Some(ShippingAddress {
          Phone: None,
          StateOrRegion: "CA".to_string(),
          City: "SAN MATEO".to_string(),
          CountryCode: "US".to_string(),
          PostalCode: "92683-4617".to_string(),
          Name: "First Last".to_string(),
          AddressLine1: "8888 J AVE".to_string(),
          AddressLine2: "".to_string(),
        }),
        BuyerCounty: "".to_string(),
        EarliestDeliveryDate: Some("2018-12-20T08:00:00Z".parse().unwrap()),
        LatestDeliveryDate: Some("2018-12-27T07:59:59Z".parse().unwrap()),
        EasyShipShipmentStatus: "".to_owned(),
        IsEstimatedShipDateSet: false,
        IsReplacementOrder: false,
        ReplacedOrderId: "".to_owned(),
        OrderChannel: "".to_owned(),
        PromiseResponseDueDate: None,
        PurchaseOrderNumber: "".to_owned(),
        ShippedByAmazonTFM: false,
        TFMShipmentStatus: "".to_owned(),
      }
    );
  }

  #[test]
  fn test_decode_orderitem() {
    test_decode!(
      OrderItem,
      r#"<QuantityOrdered>1</QuantityOrdered>
        <Title>Edifier R1280T Powered Bookshelf Speakers - 2.0 Active Near Field Monitors - Studio Monitor Speaker - Wooden Enclosure - 42 Watts RMS</Title>
        <PromotionDiscount>
          <CurrencyCode>USD</CurrencyCode>
          <Amount>0.00</Amount>
        </PromotionDiscount>
        <ASIN>B016P9HJIA</ASIN>
        <SellerSKU>edifier-r1280t-fba</SellerSKU>
        <OrderItemId>46510268396154</OrderItemId>
        <QuantityShipped>1</QuantityShipped>
        <ItemPrice>
          <CurrencyCode>USD</CurrencyCode>
          <Amount>99.99</Amount>
        </ItemPrice>
        <ItemTax>
          <CurrencyCode>USD</CurrencyCode>
          <Amount>0.00</Amount>
        </ItemTax>"#,
      OrderItem {
        OrderItemId: "46510268396154".to_string(),
        QuantityOrdered: 1,
        Title: "Edifier R1280T Powered Bookshelf Speakers - 2.0 Active Near Field Monitors - Studio Monitor Speaker - Wooden Enclosure - 42 Watts RMS".to_string(),
        ASIN: "B016P9HJIA".to_string(),
        SellerSKU: "edifier-r1280t-fba".to_string(),
        QuantityShipped: 1,
        ItemPrice: Some(CurrencyAmount { CurrencyCode: "USD".to_string(), Amount: "99.99".to_owned() }),
        ItemTax: Some(CurrencyAmount { CurrencyCode: "USD".to_string(), Amount: "0.00".to_owned() }),
        GiftWrapPrice: None,
        GiftWrapTax: None,
        PromotionDiscount: Some(CurrencyAmount { CurrencyCode: "USD".to_string(), Amount: "0.00".to_owned() }),
        ShippingPrice: None,
        ShippingDiscount: None,
        ShippingTax: None,
      }
    );
  }
}
<commit_msg>add OrderItem::IsTransparency<commit_after>use chrono::{DateTime, Utc};

#[allow(non_snake_case)]
#[derive(Debug, Default, PartialEq, Serialize, FromXmlStream)]
pub struct ShippingAddress {
  pub StateOrRegion: String,
  pub City: String,
  pub CountryCode: String,
  pub PostalCode: String,
  pub Name: String,
  pub AddressLine1: String,
  pub AddressLine2: String,
  pub Phone: Option<String>,
}

#[allow(non_snake_case)]
#[derive(Debug, Default, PartialEq, Serialize, FromXmlStream)]
pub struct CurrencyAmount {
  pub CurrencyCode: String,
  pub Amount: String,
}

#[allow(non_snake_case)]
#[derive(Debug, Default, PartialEq, Serialize, FromXmlStream)]
pub struct Order {
  /// An Amazon-defined order identifier, in 3-7-7 format.
  pub AmazonOrderId: String,
  /// A seller-defined order identifier.
  pub SellerOrderId: String,
  /// The date when the order was created.
  pub PurchaseDate: Option<DateTime<Utc>>,
  /// The date when the order was last updated.
  pub LastUpdateDate: Option<DateTime<Utc>>,
  /// The current order status.
  pub OrderStatus: OrderStatus,
  /// How the order was fulfilled: by Amazon (AFN) or by the seller (MFN).
  pub FulfillmentChannel: FulfillmentChannel,
  /// The sales channel of the first item in the order.
  pub SalesChannel: String,
  /// The order channel of the first item in the order.
  pub OrderChannel: String,
  /// The shipment service level of the order.
  pub ShipServiceLevel: String,
  /// The shipping address for the order.
  pub ShippingAddress: Option<ShippingAddress>,
  /// The total charge for the order.
  pub OrderTotal: Option<CurrencyAmount>,
  /// The number of items shipped.
  pub NumberOfItemsShipped: i32,
  /// The number of items unshipped.
  pub NumberOfItemsUnshipped: i32,

  // pub PaymentExecutionDetail: ?
  /// The payment method for the order.
  /// This response element is limited to Cash On Delivery (COD)
  /// and Convenience Store (CVS) payment methods.
  /// Unless you need the specific COD payment information provided
  /// by the PaymentExecutionDetailItem element, we recommend using
  /// the PaymentMethodDetails response element to get payment
  /// method information.
  pub PaymentMethod: PaymentMethod,

  // pub PaymentMethodDetails: ?
  /// true if this is a replacement order.
  pub IsReplacementOrder: bool,
  /// The AmazonOrderId value for the order that is being replaced.
  pub ReplacedOrderId: String,
  /// The anonymized identifier for the Marketplace where the order was placed.
  pub MarketplaceId: String,
  /// The anonymized e-mail address of the buyer.
  pub BuyerEmail: String,
  /// The name of the buyer.
  pub BuyerName: String,
  /// The county of the buyer.
  /// This element is used only in the Brazil marketplace.
  pub BuyerCounty: String,

  // pub BuyerTaxInfo: ?
  /// The shipment service level category of the order.
  /// ShipmentServiceLevelCategory values: Expedited, FreeEconomy, NextDay, SameDay, SecondDay, Scheduled, Standard
  pub ShipmentServiceLevelCategory: String,
  /// true if the order was shipped by the Amazon Transportation for Merchants (Amazon TFM) service.
  /// Amazon TFM is available only in the China marketplace.
  pub ShippedByAmazonTFM: bool,
  /// The status of the Amazon TFM order. Returned only if
  /// ShippedByAmazonTFM = True. Note that even if ShippedByAmazonTFM = True,
  /// TFMShipmentStatus will not be returned if you have
  /// not yet created the shipment.
  /// TFMShipmentStatus values: PendingPickUp, LabelCanceled, PickedUp,
  /// AtDestinationFC, Delivered, RejectedByBuyer, Undeliverable,
  /// ReturnedToSeller
  /// Amazon TFM is available only in the China marketplace.
  pub TFMShipmentStatus: String,
  /// The status of the Amazon Easy Ship order.
  /// This element is included only for Amazon Easy Ship orders.
  /// EasyShipShipmentStatus values: PendingPickUp, LabelCanceled,
  /// PickedUp, OutForDelivery, Damaged, Delivered, RejectedByBuyer,
  /// Undeliverable, ReturnedToSeller
  /// Amazon Easy Ship is available only in the India marketplace.
  pub EasyShipShipmentStatus: String,
  /// The type of the order.
  pub OrderType: String,
  /// The start of the time period that you have committed to
  /// ship the order. In ISO 8601 date time format.
  pub EarliestShipDate: Option<DateTime<Utc>>,
  /// The end of the time period that you have committed to ship
  /// the order. In ISO 8601 date time format.
  pub LatestShipDate: Option<DateTime<Utc>>,
  /// The start of the time period that you have commited to fulfill
  /// the order. In ISO 8601 date time format.
  pub EarliestDeliveryDate: Option<DateTime<Utc>>,
  /// The end of the time period that you have commited to fulfill the order.
  /// In ISO 8601 date time format.
  pub LatestDeliveryDate: Option<DateTime<Utc>>,
  /// true if the order is an Amazon Business order.
  /// An Amazon Business order is an order where the buyer is a
  /// Verified Business Buyer and the seller is an Amazon Business Seller.
  /// For more information about the Amazon Business Seller Program,
  /// see the Amazon Business website.
  pub IsBusinessOrder: bool,
  /// The purchase order (PO) number entered by the buyer at checkout.
  pub PurchaseOrderNumber: String,
  /// true if the order is a seller-fulfilled Amazon Prime order.
  pub IsPrime: bool,
  /// true if the order has a Premium Shipping Service Level Agreement.
  /// For more information about Premium Shipping orders,
  /// see "Premium Shipping Options" in the Seller Central Help for
  /// your marketplace.
  pub IsPremiumOrder: bool,
  /// Indicates the date by which the seller must respond to the buyer
  /// with an Estimated Ship Date.
  pub PromiseResponseDueDate: Option<DateTime<Utc>>,
  /// true if the Estimated Ship Date is set for the order.
  pub IsEstimatedShipDateSet: bool,
}

str_enum! {
  /// A list of OrderStatus values. Used to select orders with a current status that matches
  /// one of the status values that you specify.
  ///
  /// Unshipped and PartiallyShipped must be used together in this version of the Orders API
  /// section. Using one and not the other returns an error.
  ///
  /// [Reference](http://docs.developer.amazonservices.com/en_CA/orders-2013-09-01/Orders_ListOrders.html)
  pub enum OrderStatus {
    PendingAvailability,
    Pending,
    Unshipped,
    PartiallyShipped,
    Shipped,
    InvoiceUnconfirmed,
    Canceled,
    Unfulfillable,
  }
}

str_enum! {
  ///	A list that indicates how an order was fulfilled.
  ///
  /// [Reference](http://docs.developer.amazonservices.com/en_CA/orders-2013-09-01/Orders_ListOrders.html)
  pub enum FulfillmentChannel {
    AFN,
    MFN,
  }
}

str_enum! {
  /// A list of PaymentMethod values. Used to select orders paid for with the payment methods
  /// that you specify.
  ///
  /// Note: COD and CVS values are valid only in Japan (JP).
  pub enum PaymentMethod {
    COD,
    CVS,
    Other,
  }
}

str_enum! {
  /// A list of TFMShipmentStatus values. Used to select Amazon Transportation for Merchants (TFM)
  /// orders with a current status that matches one of the status values that you specify.
  /// If TFMShipmentStatus is specified, only TFM orders are returned.
  ///
  /// Note: The TFMShipmentStatus request parameter is available only in China (CN).
  pub enum TFMShipmentStatus {
    PendingPickUp,
    LabelCanceled,
    PickedUp,
    AtDestinationFC,
    Delivered,
    RejectedByBuyer,
    Undeliverable,
    ReturnedToSeller,
    Lost,
  }
}

#[allow(non_snake_case)]
#[derive(Debug, Default, PartialEq, Serialize, FromXmlStream)]
pub struct OrderItem {
  pub OrderItemId: String,
  pub QuantityOrdered: i32,
  pub Title: String,
  pub ASIN: String,
  pub SellerSKU: String,
  pub QuantityShipped: i32,
  pub ItemPrice: Option<CurrencyAmount>,
  pub ItemTax: Option<CurrencyAmount>,
  pub GiftWrapPrice: Option<CurrencyAmount>,
  pub GiftWrapTax: Option<CurrencyAmount>,
  pub PromotionDiscount: Option<CurrencyAmount>,
  pub ShippingPrice: Option<CurrencyAmount>,
  pub ShippingDiscount: Option<CurrencyAmount>,
  pub ShippingTax: Option<CurrencyAmount>,
  pub IsTransparency: bool,
}

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

  #[test]
  fn test_decode_order() {
    test_decode!(
      Order,
      r#"
        <LatestShipDate>2018-12-18T07:59:59Z</LatestShipDate>
        <OrderType>StandardOrder</OrderType>
        <SellerOrderId>666</SellerOrderId>
        <PurchaseDate>2018-12-16T18:53:45.856Z</PurchaseDate>
        <AmazonOrderId>111-3081581-6666666</AmazonOrderId>
        <BuyerEmail>666@marketplace.amazon.com</BuyerEmail>
        <IsReplacementOrder>false</IsReplacementOrder>
        <LastUpdateDate>2018-12-17T16:50:11.820Z</LastUpdateDate>
        <NumberOfItemsShipped>1</NumberOfItemsShipped>
        <ShipServiceLevel>Std US D2D Dom</ShipServiceLevel>
        <OrderStatus>Shipped</OrderStatus>
        <SalesChannel>Amazon.com</SalesChannel>
        <ShippedByAmazonTFM>false</ShippedByAmazonTFM>
        <IsBusinessOrder>false</IsBusinessOrder>
        <LatestDeliveryDate>2018-12-27T07:59:59Z</LatestDeliveryDate>
        <NumberOfItemsUnshipped>0</NumberOfItemsUnshipped>
        <PaymentMethodDetails>
          <PaymentMethodDetail>Standard</PaymentMethodDetail>
        </PaymentMethodDetails>
        <BuyerName>First Last</BuyerName>
        <EarliestDeliveryDate>2018-12-20T08:00:00Z</EarliestDeliveryDate>
        <OrderTotal>
          <CurrencyCode>USD</CurrencyCode>
          <Amount>666.66</Amount>
        </OrderTotal>
        <IsPremiumOrder>false</IsPremiumOrder>
        <EarliestShipDate>2018-12-17T08:00:00Z</EarliestShipDate>
        <MarketplaceId>ATVPDKIKX0DER</MarketplaceId>
        <FulfillmentChannel>MFN</FulfillmentChannel>
        <PaymentMethod>Other</PaymentMethod>
        <ShippingAddress>
          <City>SAN MATEO</City>
          <AddressType>Residential</AddressType>
          <PostalCode>92683-4617</PostalCode>
          <isAddressSharingConfidential>false</isAddressSharingConfidential>
          <StateOrRegion>CA</StateOrRegion>
          <CountryCode>US</CountryCode>
          <Name>First Last</Name>
          <AddressLine1>8888 J AVE</AddressLine1>
        </ShippingAddress>
        <IsPrime>true</IsPrime>
        <ShipmentServiceLevelCategory>Standard</ShipmentServiceLevelCategory>"#,
      Order {
        LatestShipDate: Some(
          "2018-12-18T07:59:59Z"
            .parse()
            .expect("parse LatestShipDate",)
        ),
        OrderType: "StandardOrder".to_string(),
        PurchaseDate: Some(
          "2018-12-16T18:53:45.856Z"
            .parse()
            .expect("parse PurchaseDate")
        ),
        AmazonOrderId: "111-3081581-6666666".to_string(),
        LastUpdateDate: Some(
          "2018-12-17T16:50:11.820Z"
            .parse()
            .expect("parse LastUpdateDate",)
        ),
        ShipServiceLevel: "Std US D2D Dom".to_string(),
        NumberOfItemsShipped: 1,
        OrderStatus: OrderStatus::Shipped,
        SalesChannel: "Amazon.com".to_string(),
        IsBusinessOrder: false,
        NumberOfItemsUnshipped: 0,
        IsPremiumOrder: false,
        EarliestShipDate: Some(
          "2018-12-17T08:00:00Z"
            .parse()
            .expect("parse EarliestShipDate",)
        ),
        MarketplaceId: "ATVPDKIKX0DER".to_string(),
        FulfillmentChannel: FulfillmentChannel::MFN,
        PaymentMethod: PaymentMethod::Other,
        IsPrime: true,
        ShipmentServiceLevelCategory: "Standard".to_string(),
        SellerOrderId: "666".to_string(),
        BuyerEmail: "666@marketplace.amazon.com".to_string(),
        BuyerName: "First Last".to_string(),
        OrderTotal: Some(CurrencyAmount {
          CurrencyCode: "USD".to_string(),
          Amount: "666.66".to_owned(),
        }),
        ShippingAddress: Some(ShippingAddress {
          Phone: None,
          StateOrRegion: "CA".to_string(),
          City: "SAN MATEO".to_string(),
          CountryCode: "US".to_string(),
          PostalCode: "92683-4617".to_string(),
          Name: "First Last".to_string(),
          AddressLine1: "8888 J AVE".to_string(),
          AddressLine2: "".to_string(),
        }),
        BuyerCounty: "".to_string(),
        EarliestDeliveryDate: Some("2018-12-20T08:00:00Z".parse().unwrap()),
        LatestDeliveryDate: Some("2018-12-27T07:59:59Z".parse().unwrap()),
        EasyShipShipmentStatus: "".to_owned(),
        IsEstimatedShipDateSet: false,
        IsReplacementOrder: false,
        ReplacedOrderId: "".to_owned(),
        OrderChannel: "".to_owned(),
        PromiseResponseDueDate: None,
        PurchaseOrderNumber: "".to_owned(),
        ShippedByAmazonTFM: false,
        TFMShipmentStatus: "".to_owned(),
      }
    );
  }

  #[test]
  fn test_decode_orderitem() {
    test_decode!(
      OrderItem,
      r#"<QuantityOrdered>1</QuantityOrdered>
        <Title>Edifier R1280T Powered Bookshelf Speakers - 2.0 Active Near Field Monitors - Studio Monitor Speaker - Wooden Enclosure - 42 Watts RMS</Title>
        <PromotionDiscount>
          <CurrencyCode>USD</CurrencyCode>
          <Amount>0.00</Amount>
        </PromotionDiscount>
        <ASIN>B016P9HJIA</ASIN>
        <SellerSKU>edifier-r1280t-fba</SellerSKU>
        <OrderItemId>46510268396154</OrderItemId>
        <QuantityShipped>1</QuantityShipped>
        <ItemPrice>
          <CurrencyCode>USD</CurrencyCode>
          <Amount>99.99</Amount>
        </ItemPrice>
        <ItemTax>
          <CurrencyCode>USD</CurrencyCode>
          <Amount>0.00</Amount>
        </ItemTax>"#,
      OrderItem {
        OrderItemId: "46510268396154".to_string(),
        QuantityOrdered: 1,
        Title: "Edifier R1280T Powered Bookshelf Speakers - 2.0 Active Near Field Monitors - Studio Monitor Speaker - Wooden Enclosure - 42 Watts RMS".to_string(),
        ASIN: "B016P9HJIA".to_string(),
        SellerSKU: "edifier-r1280t-fba".to_string(),
        QuantityShipped: 1,
        ItemPrice: Some(CurrencyAmount { CurrencyCode: "USD".to_string(), Amount: "99.99".to_owned() }),
        ItemTax: Some(CurrencyAmount { CurrencyCode: "USD".to_string(), Amount: "0.00".to_owned() }),
        GiftWrapPrice: None,
        GiftWrapTax: None,
        PromotionDiscount: Some(CurrencyAmount { CurrencyCode: "USD".to_string(), Amount: "0.00".to_owned() }),
        ShippingPrice: None,
        ShippingDiscount: None,
        ShippingTax: None,
      }
    );
  }
}
<|endoftext|>


<commit_before>use std::collections::LinkedList;
use std::time::{SystemTime, UNIX_EPOCH};
use std::cmp::Ordering;

pub enum AcquireResult {
    Limited,
    Free,
}

pub struct RateLimiter {
    call_times: LinkedList<u64>,
    window_size: u64, // seconds
    limit: u32
}

impl RateLimiter {
    pub fn acquire(&mut self) -> AcquireResult {
        let now_time = SystemTime::now();
        let now_seconds = now_time.duration_since(UNIX_EPOCH).unwrap().as_secs();
        self.call_times.push_back(now_seconds);
        let mut redundant_calls_count = 0;
        for call_time in self.call_times.iter() {
            if now_seconds - call_time >= self.window_size {
                redundant_calls_count += 1;
            } else {
                break;
            }
        }
        for _ in 0..redundant_calls_count {
            self.call_times.pop_front();
        }
        return match self.call_times.len().cmp(&(self.limit as usize)) {
            Ordering::Greater => AcquireResult::Limited,
            _ => AcquireResult::Free
        };
    }

    pub fn new(window_size: u64, limit: u32) -> RateLimiter {
        return RateLimiter {
            window_size: window_size,
            limit: limit,
            call_times: LinkedList::new()
        }
    }
}
<commit_msg>Expect instead of unwrap<commit_after>use std::collections::LinkedList;
use std::time::{SystemTime, UNIX_EPOCH};
use std::cmp::Ordering;

pub enum AcquireResult {
    Limited,
    Free,
}

pub struct RateLimiter {
    call_times: LinkedList<u64>,
    window_size: u64, // seconds
    limit: u32
}

impl RateLimiter {
    pub fn acquire(&mut self) -> AcquireResult {
        let now_time = SystemTime::now();
        let now_seconds = now_time.duration_since(UNIX_EPOCH)
                                  .expect("Failed to get duration since epoch")
                                  .as_secs();
        self.call_times.push_back(now_seconds);
        let mut redundant_calls_count = 0;
        for call_time in self.call_times.iter() {
            if now_seconds - call_time >= self.window_size {
                redundant_calls_count += 1;
            } else {
                break;
            }
        }
        for _ in 0..redundant_calls_count {
            self.call_times.pop_front();
        }
        return match self.call_times.len().cmp(&(self.limit as usize)) {
            Ordering::Greater => AcquireResult::Limited,
            _ => AcquireResult::Free
        };
    }

    pub fn new(window_size: u64, limit: u32) -> RateLimiter {
        return RateLimiter {
            window_size: window_size,
            limit: limit,
            call_times: LinkedList::new()
        }
    }
}
<|endoftext|>


<commit_before>use libc::{c_int, c_char, c_long, time_t, size_t};
use data_structs::{JTM};
use jalali_bindings::*;
use std::ffi::CString;
use std::{mem, ptr};

pub struct JTMBuilder {
  pub tm_sec: i32,
  pub tm_min: i32,
  pub tm_hour: i32,
  pub tm_mday: i32,
  pub tm_mon: i32,
  pub tm_year: i32,
  pub tm_wday: i32,
  pub tm_yday: i32,
  pub tm_isdst: i32,
  pub tm_gmtoff: i64,
  pub tm_zone: String,
}

impl JTMBuilder {
  pub fn new() -> Self {
    JTMBuilder {
      tm_sec: 0,
      tm_min: 0,
      tm_hour: 0,
      tm_mday: 0,
      tm_mon: 0,
      tm_year: 0,
      tm_wday: 0,
      tm_yday: 0,
      tm_isdst: 0,
      tm_gmtoff: 0,
      tm_zone: "".to_string(),
    }
  }

  pub fn set_sec(&mut self, sec: i32) -> &mut Self {
    self.tm_sec = sec;
    self
  }

  pub fn set_min(&mut self, min: i32) -> &mut Self {
    self.tm_min = min;
    self
  }

  pub fn set_hour(&mut self, hour: i32) -> &mut Self {
    self.tm_hour = hour;
    self
  }

  pub fn set_mday(&mut self, mday: i32) -> &mut Self {
    self.tm_mday = mday;
    self
  }

  pub fn set_mon(&mut self, mon: i32) -> &mut Self {
    self.tm_mon = mon;
    self
  }

  pub fn set_year(&mut self, year: i32) -> &mut Self {
    self.tm_year = year;
    self
  }

  pub fn set_wday(&mut self, wday: i32) -> &mut Self {
    self.tm_wday = wday;
    self
  }

  pub fn set_yday(&mut self, yday: i32) -> &mut Self {
    self.tm_yday = yday;
    self
  }

  pub fn set_isdst(&mut self, isdst: i32) -> &mut Self {
    self.tm_isdst = isdst;
    self
  }

  pub fn set_gmtoff(&mut self, gmtoff: i64) -> &mut Self {
    self.tm_gmtoff = gmtoff;
    self
  }

  pub fn set_zone(&mut self, zone: String) -> &mut Self {
    self.tm_zone = zone;
    self
  }

  pub fn build(&self) -> JTM {
    JTM {
      tm_sec: self.tm_sec,
      tm_min: self.tm_min,
      tm_hour: self.tm_hour,
      tm_mday: self.tm_mday,
      tm_mon: self.tm_mon,
      tm_year: self.tm_year,
      tm_wday: self.tm_wday,
      tm_yday: self.tm_yday,
      tm_isdst: self.tm_isdst,
      tm_gmtoff: self.tm_gmtoff,
      tm_zone: CString::new(self.tm_zone.clone().into_bytes()).
                                                 unwrap().
                                                 into_raw(),
    }
  }
}
<commit_msg>define JTM methods (JTM related safe wrappers)<commit_after>use libc::{c_int, c_char, c_long, time_t, size_t};
use data_structs::{JTM};
use jalali_bindings::*;
use std::ffi::CString;
use std::{mem, ptr};

pub struct JTMBuilder {
  pub tm_sec: i32,
  pub tm_min: i32,
  pub tm_hour: i32,
  pub tm_mday: i32,
  pub tm_mon: i32,
  pub tm_year: i32,
  pub tm_wday: i32,
  pub tm_yday: i32,
  pub tm_isdst: i32,
  pub tm_gmtoff: i64,
  pub tm_zone: String,
}

impl JTMBuilder {
  pub fn new() -> Self {
    JTMBuilder {
      tm_sec: 0,
      tm_min: 0,
      tm_hour: 0,
      tm_mday: 0,
      tm_mon: 0,
      tm_year: 0,
      tm_wday: 0,
      tm_yday: 0,
      tm_isdst: 0,
      tm_gmtoff: 0,
      tm_zone: "".to_string(),
    }
  }

  pub fn set_sec(&mut self, sec: i32) -> &mut Self {
    self.tm_sec = sec;
    self
  }

  pub fn set_min(&mut self, min: i32) -> &mut Self {
    self.tm_min = min;
    self
  }

  pub fn set_hour(&mut self, hour: i32) -> &mut Self {
    self.tm_hour = hour;
    self
  }

  pub fn set_mday(&mut self, mday: i32) -> &mut Self {
    self.tm_mday = mday;
    self
  }

  pub fn set_mon(&mut self, mon: i32) -> &mut Self {
    self.tm_mon = mon;
    self
  }

  pub fn set_year(&mut self, year: i32) -> &mut Self {
    self.tm_year = year;
    self
  }

  pub fn set_wday(&mut self, wday: i32) -> &mut Self {
    self.tm_wday = wday;
    self
  }

  pub fn set_yday(&mut self, yday: i32) -> &mut Self {
    self.tm_yday = yday;
    self
  }

  pub fn set_isdst(&mut self, isdst: i32) -> &mut Self {
    self.tm_isdst = isdst;
    self
  }

  pub fn set_gmtoff(&mut self, gmtoff: i64) -> &mut Self {
    self.tm_gmtoff = gmtoff;
    self
  }

  pub fn set_zone(&mut self, zone: String) -> &mut Self {
    self.tm_zone = zone;
    self
  }

  pub fn build(&self) -> JTM {
    JTM {
      tm_sec: self.tm_sec,
      tm_min: self.tm_min,
      tm_hour: self.tm_hour,
      tm_mday: self.tm_mday,
      tm_mon: self.tm_mon,
      tm_year: self.tm_year,
      tm_wday: self.tm_wday,
      tm_yday: self.tm_yday,
      tm_isdst: self.tm_isdst,
      tm_gmtoff: self.tm_gmtoff,
      tm_zone: CString::new(self.tm_zone.clone().into_bytes()).
                                                 unwrap().
                                                 into_raw(),
    }
  }
}

impl JTM {
  pub fn from_secs(secs: i64) -> Self {
    let mut result: Self;
    unsafe {
      result = mem::uninitialized();
      jlocaltime_r(&secs as *const time_t, &mut result);
    }
    result
  }

  pub fn from_days(days: i32) -> Self {
    let mut result: Self;
    unsafe {
      result = mem::uninitialized();
      jalali_get_date(days as c_int, &mut result);
    }
    result
  }

  pub fn from_secs_to_utc(secs: i64) -> Self {
    let mut result: Self;
    unsafe {
      result = mem::uninitialized();
      jgmtime_r(&secs as *const time_t, &mut result);
    }
    result
  }

  pub fn from_formatted_string(s: &String, format: &String) -> Result<Self,()> {
    let mut result: Self;
    let tmp;
    unsafe {
      result = mem::uninitialized();
      tmp = jstrptime(s.as_ptr() as *const i8,
                      format.as_ptr() as *const i8,
                      &mut result);
    }
    result.update();
    if tmp.is_null() {
      Err(())
    } else {
      Ok(result)
    }
  }

  pub fn create_date_from_days(&mut self) -> Result<(),()> {
    let tmp = unsafe {
      jalali_create_date_from_days(self)
    };
    match tmp {
      -1 => Err(()),
      _ => Ok(()),
    }
  }

  pub fn create_days_from_date(&mut self) -> Result<(),()> {
    let tmp = unsafe {
      jalali_create_days_from_date(self)
    };
    match tmp {
      -1 => Err(()),
      _ => Ok(()),
    }
  }

  pub fn get_diff(&self) -> i32 {
    unsafe {
      jalali_get_diff(self)
    }
  }

  pub fn update(&mut self) {
    unsafe {
      jalali_update(self);
    }
  }

  pub fn show_time(&self) {
    unsafe {
      jalali_show_time(self);
    }
  }

  pub fn to_string(&self) -> String {
    let mut buff = Vec::<u8>::with_capacity(100);
    let mut result: String;
    unsafe {
      jasctime_r(self, buff.as_mut_ptr() as *mut i8);
      result = CString::from_raw(buff.as_mut_ptr() as *mut i8).into_string().unwrap();
    }
    mem::forget(buff);
    return result;
  }

  pub fn to_secs(&mut self) -> i64 {
    unsafe {
      jmktime(self)
    }
  }

  pub fn make_formated_string(&self, format: &String, buff: &mut String) -> usize {
    let mut b = String::with_capacity(buff.capacity()).into_bytes();
    let retval: usize;
    unsafe {
      let f = format.as_ptr() as *const i8;
      let max = b.capacity() as size_t;
      retval = jstrftime(b.as_mut_ptr() as *mut i8, max, f, self);
      let tmp = CString::from_raw(b.as_mut_ptr() as *mut i8).into_string().unwrap();
      ptr::copy_nonoverlapping(&tmp, buff, 1);
      mem::forget(tmp);
    }
    mem::forget(b);
    return retval;
  }
}
<|endoftext|>


<commit_before>extern crate image;
extern crate time;

use std::iter;
use std::path::Path;

use vector::*;
use objects::*;
mod lighting;

pub type Image = image::RgbImage;

pub fn write_image(image: Image, filename: &str) {
    let _ = image.save(&Path::new(filename));
}

pub fn raytrace(scene: &Scene, width: u32, height: u32, h_fov: f64) {
    let f_width = width as f64;
    let f_height = height as f64;
    let v_fov = h_fov * (f_height / f_width);

    let vw_per_pixel = 2.0 * (h_fov / 2.0).tan() / f_width;
    let vh_per_pixel = 2.0 * (v_fov / 2.0).tan() / f_height;

    let norm_up = scene.camera.up.normalized();
    let norm_right = scene.camera.direction.cross(scene.camera.up).normalized();

    let mut image = image::RgbImage::new(width, height);
    let start_time = time::precise_time_ns();

    let mut rays: u64 = 0;

    let tracer = |image: &mut image::RgbImage, rays: &mut u64| {
        let coords = (0..width).flat_map(|y| {
            iter::repeat(y).zip(0..height)
        });
        let trace_coord = |coord| {
            let (x, y) = coord;
            let cast_ray = |dx: f64, dy: f64, rays: &mut u64| {
                *rays += 1;
                let fi = (x as f64) + dx;
                let fj = (y as f64) + dy;

                let u_rel = vw_per_pixel * (fi - (f_width / 2.0));
                let v_rel = vh_per_pixel * (fj - (f_height / 2.0));

                let pixel_loc = scene.camera.position + scene.camera.direction +
                    (norm_right * u_rel) + (norm_up * v_rel);

                let ray = Ray {
                    origin: scene.camera.position,
                    direction: pixel_loc - scene.camera.position
                };

                let (color, new_rays) = lighting::get_color(&scene, &ray, 3);
                *rays += new_rays;
                color
            };

            let c1 = cast_ray(0.25, 0.25, rays);
            let c2 = cast_ray(0.75, 0.25, rays);
            let c3 = cast_ray(0.50, 0.50, rays);
            let c4 = cast_ray(0.75, 0.75, rays);
            let c5 = cast_ray(0.25, 0.75, rays);

            (coord, (c1 + c2 + c3 + c4 + c5) / 5.0)
        };
        for ((x, y), pixel) in coords.map(trace_coord) {
            image.put_pixel(x as u32, y as u32, pixel.to_rgb());
        }
    };
    tracer(&mut image, &mut rays);

    write_image(image, "test.png");

    let elapsed_time = ((time::precise_time_ns() - start_time) as f64) /
        1000000.0;
    let rays_per_s = 1000.0 * (rays as f64) / elapsed_time;
    println!("Traced {} rays in {} ms ({} rays per second).",
             rays, elapsed_time, rays_per_s);
}
<commit_msg>Further refactor tracing loop in anticipation of threading<commit_after>extern crate image;
extern crate time;

use std::iter;
use std::path::Path;
use std::thread;

use vector::*;
use objects::*;
mod lighting;

pub type Image = image::RgbImage;

pub fn write_image(image: Image, filename: &str) {
    let _ = image.save(&Path::new(filename));
}

pub fn raytrace(scene: &Scene, width: u32, height: u32, h_fov: f64) {
    let f_width = width as f64;
    let f_height = height as f64;
    let v_fov = h_fov * (f_height / f_width);

    let vw_per_pixel = 2.0 * (h_fov / 2.0).tan() / f_width;
    let vh_per_pixel = 2.0 * (v_fov / 2.0).tan() / f_height;

    let norm_up = scene.camera.up.normalized();
    let norm_right = scene.camera.direction.cross(scene.camera.up).normalized();

    let mut image = image::RgbImage::new(width, height);
    let start_time = time::precise_time_ns();

    let mut rays = 0;

    let tracer = |rays: &mut u64, row_start, num_rows| {
        let coords = (0..width).flat_map(|y| {
            iter::repeat(y).zip(row_start..num_rows)
        });
        let trace_coord = |coord| {
            let (x, y) = coord;
            let cast_ray = |dx: f64, dy: f64, rays: &mut u64| {
                *rays += 1;
                let fi = (x as f64) + dx;
                let fj = (y as f64) + dy;

                let u_rel = vw_per_pixel * (fi - (f_width / 2.0));
                let v_rel = vh_per_pixel * (fj - (f_height / 2.0));

                let pixel_loc = scene.camera.position + scene.camera.direction +
                    (norm_right * u_rel) + (norm_up * v_rel);

                let ray = Ray {
                    origin: scene.camera.position,
                    direction: pixel_loc - scene.camera.position
                };

                let (color, new_rays) = lighting::get_color(&scene, &ray, 3);
                *rays += new_rays;
                color
            };

            let c1 = cast_ray(0.25, 0.25, rays);
            let c2 = cast_ray(0.75, 0.25, rays);
            let c3 = cast_ray(0.50, 0.50, rays);
            let c4 = cast_ray(0.75, 0.75, rays);
            let c5 = cast_ray(0.25, 0.75, rays);

            (coord, (c1 + c2 + c3 + c4 + c5) / 5.0)
        };

        let mut result = Vec::with_capacity((num_rows * width) as usize);
        for pixel in coords.map(trace_coord) {
            result.push(pixel)
        }

        result
    };

    let pixels = tracer(&mut rays, 0, height);

    for ((x, y), pixel) in pixels {
        image.put_pixel(x as u32, y as u32, pixel.to_rgb());
    }

    write_image(image, "test.png");

    let elapsed_time = ((time::precise_time_ns() - start_time) as f64) /
        1000000.0;
    let rays_per_s = 1000.0 * (rays as f64) / elapsed_time;
    println!("Traced {} rays in {} ms ({} rays per second).",
             rays, elapsed_time, rays_per_s);
}
<|endoftext|>


<commit_before>use prelude::*;

cfg_if! {
    if #[cfg(feature = "std")] {
        use std::fmt;
        use std::str;
    } else {
        use core::fmt;
        use core::str;
    }
}

impl fmt::Display for Uuid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl fmt::Display for UuidVariant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            UuidVariant::NCS => write!(f, "NCS"),
            UuidVariant::RFC4122 => write!(f, "RFC4122"),
            UuidVariant::Microsoft => write!(f, "Microsoft"),
            UuidVariant::Future => write!(f, "Future"),
        }
    }
}

impl fmt::LowerHex for Uuid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        <super::Hyphenated as fmt::LowerHex>::fmt(&self.hyphenated(), f)
    }
}

impl fmt::UpperHex for Uuid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        <super::Hyphenated as fmt::UpperHex>::fmt(&self.hyphenated(), f)
    }
}

impl str::FromStr for Uuid {
    type Err = super::ParseError;

    fn from_str(uuid_str: &str) -> Result<Uuid, super::ParseError> {
        Uuid::parse_str(uuid_str)
    }
}

impl Default for Uuid {
    fn default() -> Self {
        Uuid::nil()
    }
}

#[cfg(test)]
mod tests {
    extern crate std;

    use self::std::prelude::*;
    use prelude::*;
    use test_util;

    macro_rules! check {
        ($buf:ident, $format:expr, $target:expr, $len:expr, $cond:expr) => {
            $buf.clear();
            write!($buf, $format, $target).unwrap();
            assert!($buf.len() == $len);
            assert!($buf.chars().all($cond), "{}", $buf);
        };
    }

    #[test]
    fn test_uuid_compare() {
        let uuid1 = test_util::new();
        let uuid2 = test_util::new2();

        assert_eq!(uuid1, uuid1);
        assert_eq!(uuid2, uuid2);

        assert_ne!(uuid1, uuid2);
        assert_ne!(uuid2, uuid1);
    }

    #[test]
    fn test_uuid_default() {
        let default_uuid = Uuid::default();
        let nil_uuid = Uuid::nil();

        assert_eq!(default_uuid, nil_uuid);
    }

    #[test]
    fn test_uuid_display() {
        use super::fmt::Write;

        let uuid = test_util::new();
        let s = uuid.to_string();
        let mut buffer = String::new();

        assert_eq!(s, uuid.hyphenated().to_string());

        check!(
            buffer,
            "{}",
            uuid,
            36,
            |c| c.is_lowercase() || c.is_digit(10) || c == '-'
        );
    }

    #[test]
    fn test_uuid_lowerhex() {
        use super::fmt::Write;

        let mut buffer = String::new();
        let uuid = test_util::new();

        check!(
            buffer,
            "{:x}",
            uuid,
            36,
            |c| c.is_lowercase() || c.is_digit(10) || c == '-'
        );
    }

    #[test]
    fn test_uuid_operator_eq() {
        let uuid1 = test_util::new();
        let uuid1_dup = uuid1.clone();
        let uuid2 = test_util::new2();

        assert!(uuid1 == uuid1);
        assert!(uuid1 == uuid1_dup);
        assert!(uuid1_dup == uuid1);

        assert!(uuid1 != uuid2);
        assert!(uuid2 != uuid1);
        assert!(uuid1_dup != uuid2);
        assert!(uuid2 != uuid1_dup);
    }

    #[test]
    fn test_uuid_to_string() {
        use super::fmt::Write;

        let uuid = test_util::new();
        let s = uuid.to_string();
        let mut buffer = String::new();

        assert_eq!(s.len(), 36);

        check!(buffer, "{}", s, 36, |c| c.is_lowercase() || c.is_digit(10)
            || c == '-');
    }

    #[test]
    fn test_uuid_upperhex() {
        use super::fmt::Write;

        let mut buffer = String::new();
        let uuid = test_util::new();

        check!(
            buffer,
            "{:X}",
            uuid,
            36,
            |c| c.is_uppercase() || c.is_digit(10) || c == '-'
        );
    }
}
<commit_msg>fix tests attempt x<commit_after>use prelude::*;

cfg_if! {
    if #[cfg(feature = "std")] {
        use std::fmt;
        use std::str;
    } else {
        use core::fmt;
        use core::str;
    }
}

impl fmt::Display for Uuid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl fmt::Display for UuidVariant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            UuidVariant::NCS => write!(f, "NCS"),
            UuidVariant::RFC4122 => write!(f, "RFC4122"),
            UuidVariant::Microsoft => write!(f, "Microsoft"),
            UuidVariant::Future => write!(f, "Future"),
        }
    }
}

impl fmt::LowerHex for Uuid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        <super::Hyphenated as fmt::LowerHex>::fmt(&self.hyphenated(), f)
    }
}

impl fmt::UpperHex for Uuid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        <super::Hyphenated as fmt::UpperHex>::fmt(&self.hyphenated(), f)
    }
}

impl str::FromStr for Uuid {
    type Err = super::ParseError;

    fn from_str(uuid_str: &str) -> Result<Uuid, super::ParseError> {
        Uuid::parse_str(uuid_str)
    }
}

impl Default for Uuid {
    fn default() -> Self {
        Uuid::nil()
    }
}

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

    macro_rules! check {
        ($buf:ident, $format:expr, $target:expr, $len:expr, $cond:expr) => {
            $buf.clear();
            write!($buf, $format, $target).unwrap();
            assert!($buf.len() == $len);
            assert!($buf.chars().all($cond), "{}", $buf);
        };
    }

    #[test]
    fn test_uuid_compare() {
        let uuid1 = test_util::new();
        let uuid2 = test_util::new2();

        assert_eq!(uuid1, uuid1);
        assert_eq!(uuid2, uuid2);

        assert_ne!(uuid1, uuid2);
        assert_ne!(uuid2, uuid1);
    }

    #[test]
    fn test_uuid_default() {
        let default_uuid = Uuid::default();
        let nil_uuid = Uuid::nil();

        assert_eq!(default_uuid, nil_uuid);
    }

    #[test]
    fn test_uuid_display() {
        use super::fmt::Write;

        let uuid = test_util::new();
        let s = uuid.to_string();
        let mut buffer = String::new();

        assert_eq!(s, uuid.hyphenated().to_string());

        check!(
            buffer,
            "{}",
            uuid,
            36,
            |c| c.is_lowercase() || c.is_digit(10) || c == '-'
        );
    }

    #[test]
    fn test_uuid_lowerhex() {
        use super::fmt::Write;

        let mut buffer = String::new();
        let uuid = test_util::new();

        check!(
            buffer,
            "{:x}",
            uuid,
            36,
            |c| c.is_lowercase() || c.is_digit(10) || c == '-'
        );
    }

    #[test]
    fn test_uuid_operator_eq() {
        let uuid1 = test_util::new();
        let uuid1_dup = uuid1.clone();
        let uuid2 = test_util::new2();

        assert!(uuid1 == uuid1);
        assert!(uuid1 == uuid1_dup);
        assert!(uuid1_dup == uuid1);

        assert!(uuid1 != uuid2);
        assert!(uuid2 != uuid1);
        assert!(uuid1_dup != uuid2);
        assert!(uuid2 != uuid1_dup);
    }

    #[test]
    fn test_uuid_to_string() {
        use super::fmt::Write;

        let uuid = test_util::new();
        let s = uuid.to_string();
        let mut buffer = String::new();

        assert_eq!(s.len(), 36);

        check!(buffer, "{}", s, 36, |c| c.is_lowercase() || c.is_digit(10)
            || c == '-');
    }

    #[test]
    fn test_uuid_upperhex() {
        use super::fmt::Write;

        let mut buffer = String::new();
        let uuid = test_util::new();

        check!(
            buffer,
            "{:X}",
            uuid,
            36,
            |c| c.is_uppercase() || c.is_digit(10) || c == '-'
        );
    }
}
<|endoftext|>


<commit_before>use std::ffi::CString;
use std::mem::size_of;
use std::ptr;

use gl;
use cgmath;

use euclid::{Rect, Size2D, Point2D};

use gl::types::*;

use cgmath::Matrix;

use text::RasterizedGlyph;

static TEXT_SHADER_V: &'static str = include_str!("../../res/text.v.glsl");
static TEXT_SHADER_F: &'static str = include_str!("../../res/text.f.glsl");

pub struct QuadRenderer {
    program: ShaderProgram,
    vao: GLuint,
    vbo: GLuint,
    ebo: GLuint,
}

impl QuadRenderer {
    // TODO should probably hand this a transform instead of width/height
    pub fn new(width: u32, height: u32) -> QuadRenderer {
        let program = ShaderProgram::new(width, height);

        let mut vao: GLuint = 0;
        let mut vbo: GLuint = 0;
        let mut ebo: GLuint = 0;

        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::GenBuffers(1, &mut vbo);
            gl::GenBuffers(1, &mut ebo);
            gl::BindVertexArray(vao);

            gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
            gl::BufferData(
                gl::ARRAY_BUFFER,
                (size_of::<f32>() * 4 * 4) as GLsizeiptr,
                ptr::null(),
                gl::DYNAMIC_DRAW
            );

            let indices: [u32; 6] = [0, 1, 3,
                                     1, 2, 3];

            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo);
            gl::BufferData(gl::ELEMENT_ARRAY_BUFFER,
                           6 * size_of::<u32>() as isize,
                           indices.as_ptr() as *const _,
                           gl::STATIC_DRAW);

            gl::EnableVertexAttribArray(0);
            gl::VertexAttribPointer(0, 4, gl::FLOAT, gl::FALSE, 4 * size_of::<f32>() as i32,
                                    ptr::null());

            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0);
            gl::BindBuffer(gl::ARRAY_BUFFER, 0);
            gl::BindVertexArray(0);
        }

        QuadRenderer {
            program: program,
            vao: vao,
            vbo: vbo,
            ebo: ebo,
        }
    }

    pub fn render(&self, glyph: &Glyph, x: f32, y: f32) {
        self.program.activate();
        unsafe {
            // set color
            gl::Uniform3f(self.program.u_color, 1., 1., 0.5);
        }

        let rect = get_rect(glyph, x, y);

        // top right of character
        let vertices: [[f32; 4]; 4] = [
            [rect.max_x(), rect.max_y(), 1., 0.], // top-right
            [rect.max_x(), rect.min_y(), 1., 1.], // bottom-right
            [rect.min_x(), rect.min_y(), 0., 1.], // bottom-left
            [rect.min_x(), rect.max_y(), 0., 0.], // top-left
        ];

        unsafe {
            bind_mask_texture(glyph.tex_id);
            gl::BindVertexArray(self.vao);

            gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
            gl::BufferSubData(
                gl::ARRAY_BUFFER,
                0,
                (4 * 4 * size_of::<f32>()) as isize,
                vertices.as_ptr() as *const _
            );
            gl::BindBuffer(gl::ARRAY_BUFFER, 0);
            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.ebo);

            gl::DrawElements(gl::TRIANGLES, 6, gl::UNSIGNED_INT, ptr::null());
            gl::BindVertexArray(0);
            gl::BindTexture(gl::TEXTURE_2D, 0);
        }

        self.program.deactivate();
    }
}

fn get_rect(glyph: &Glyph, x: f32, y: f32) -> Rect<f32> {
    Rect::new(
        Point2D::new(x, y),
        Size2D::new(glyph.width as f32, glyph.height as f32)
    )
}

fn bind_mask_texture(id: u32) {
    unsafe {
        gl::ActiveTexture(gl::TEXTURE0);
        gl::BindTexture(gl::TEXTURE_2D, id);
    }
}

pub struct ShaderProgram {
    id: GLuint,
    /// projection matrix uniform
    u_projection: GLint,
    /// color uniform
    u_color: GLint,
}

impl ShaderProgram {
    pub fn activate(&self) {
        unsafe {
            gl::UseProgram(self.id);
        }
    }

    pub fn deactivate(&self) {
        unsafe {
            gl::UseProgram(0);
        }
    }

    pub fn new(width: u32, height: u32) -> ShaderProgram {
        let vertex_shader = ShaderProgram::create_vertex_shader();
        let fragment_shader = ShaderProgram::create_fragment_shader();
        let program = ShaderProgram::create_program(vertex_shader, fragment_shader);

        unsafe {
            gl::DeleteShader(vertex_shader);
            gl::DeleteShader(fragment_shader);
        }

        // get uniform locations
        let projection_str = CString::new("projection").unwrap();
        let color_str = CString::new("textColor").unwrap();

        let (projection, color) = unsafe {
            (
                gl::GetUniformLocation(program, projection_str.as_ptr()),
                gl::GetUniformLocation(program, color_str.as_ptr())
            )
        };

        assert!(projection != gl::INVALID_VALUE as i32);
        assert!(projection != gl::INVALID_OPERATION as i32);
        assert!(color != gl::INVALID_VALUE as i32);
        assert!(color != gl::INVALID_OPERATION as i32);

        let shader = ShaderProgram {
            id: program,
            u_projection: projection,
            u_color: color,
        };

        // set projection uniform
        let ortho = cgmath::ortho(0., width as f32, 0., height as f32, -1., 1.);
        let projection: [[f32; 4]; 4] = ortho.into();

        println!("width: {}, height: {}", width, height);

        shader.activate();
        unsafe {
            gl::UniformMatrix4fv(shader.u_projection,
                                 1, gl::FALSE, projection.as_ptr() as *const _);
        }
        shader.deactivate();

        shader
    }

    fn create_program(vertex: GLuint, fragment: GLuint) -> GLuint {

        unsafe {
            let program = gl::CreateProgram();
            gl::AttachShader(program, vertex);
            gl::AttachShader(program, fragment);
            gl::LinkProgram(program);

            let mut success: GLint = 0;
            gl::GetProgramiv(program, gl::LINK_STATUS, &mut success);

            if success != (gl::TRUE as GLint) {
                panic!("failed to link shader program");
            }
            program
        }
    }

    fn create_fragment_shader() -> GLuint {
        unsafe {
            let fragment_shader = gl::CreateShader(gl::FRAGMENT_SHADER);
            let fragment_source = CString::new(TEXT_SHADER_F).unwrap();
            gl::ShaderSource(fragment_shader, 1, &fragment_source.as_ptr(), ptr::null());
            gl::CompileShader(fragment_shader);

            let mut success: GLint = 0;
            gl::GetShaderiv(fragment_shader, gl::COMPILE_STATUS, &mut success);

            if success != (gl::TRUE as GLint) {
                panic!("failed to compiler fragment shader");
            }
            fragment_shader
        }
    }

    fn create_vertex_shader() -> GLuint {
        unsafe {
            let vertex_shader = gl::CreateShader(gl::VERTEX_SHADER);
            let vertex_source = CString::new(TEXT_SHADER_V).unwrap();
            gl::ShaderSource(vertex_shader, 1, &vertex_source.as_ptr(), ptr::null());
            gl::CompileShader(vertex_shader);

            let mut success: GLint = 0;
            gl::GetShaderiv(vertex_shader, gl::COMPILE_STATUS, &mut success);

            if success != (gl::TRUE as GLint) {
                panic!("failed to compiler vertex shader");
            }
            vertex_shader
        }
    }
}

#[allow(dead_code)]
pub struct Glyph {
    tex_id: GLuint,
    top: i32,
    left: i32,
    width: i32,
    height: i32,
}

impl Glyph {
    pub fn new(rasterized: &RasterizedGlyph) -> Glyph {
        let mut id: GLuint = 0;
        unsafe {
            gl::PixelStorei(gl::UNPACK_ALIGNMENT, 1);
            gl::GenTextures(1, &mut id);
            gl::BindTexture(gl::TEXTURE_2D, id);
            gl::TexImage2D(
                gl::TEXTURE_2D,
                0,
                gl::RED as i32,
                rasterized.width as i32,
                rasterized.height as i32,
                0,
                gl::RED,
                gl::UNSIGNED_BYTE,
                rasterized.buf.as_ptr() as *const _
            );

            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);

            gl::BindTexture(gl::TEXTURE_2D, 0);
        }

        Glyph {
            tex_id: id,
            top: rasterized.top as i32,
            width: rasterized.width as i32,
            height: rasterized.height as i32,
            left: rasterized.left as i32,
        }
    }
}
<commit_msg>Organize buffer data into struct<commit_after>use std::ffi::CString;
use std::mem::size_of;
use std::ptr;

use gl;
use cgmath;

use euclid::{Rect, Size2D, Point2D};

use gl::types::*;

use cgmath::Matrix;

use text::RasterizedGlyph;

static TEXT_SHADER_V: &'static str = include_str!("../../res/text.v.glsl");
static TEXT_SHADER_F: &'static str = include_str!("../../res/text.f.glsl");

pub struct QuadRenderer {
    program: ShaderProgram,
    vao: GLuint,
    vbo: GLuint,
    ebo: GLuint,
}

pub struct PackedQuad {
    pub x_tr: f32,
    pub y_tr: f32,
    pub u_tr: f32,
    pub v_tr: f32,
    pub x_br: f32,
    pub y_br: f32,
    pub u_br: f32,
    pub v_br: f32,
    pub x_bl: f32,
    pub y_bl: f32,
    pub u_bl: f32,
    pub v_bl: f32,
    pub x_tl: f32,
    pub y_tl: f32,
    pub u_tl: f32,
    pub v_tl: f32,
}

impl QuadRenderer {
    // TODO should probably hand this a transform instead of width/height
    pub fn new(width: u32, height: u32) -> QuadRenderer {
        let program = ShaderProgram::new(width, height);

        let mut vao: GLuint = 0;
        let mut vbo: GLuint = 0;
        let mut ebo: GLuint = 0;

        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::GenBuffers(1, &mut vbo);
            gl::GenBuffers(1, &mut ebo);
            gl::BindVertexArray(vao);

            gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
            gl::BufferData(
                gl::ARRAY_BUFFER,
                (size_of::<f32>() * 4 * 4) as GLsizeiptr,
                ptr::null(),
                gl::DYNAMIC_DRAW
            );

            let indices: [u32; 6] = [0, 1, 3,
                                     1, 2, 3];

            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo);
            gl::BufferData(gl::ELEMENT_ARRAY_BUFFER,
                           6 * size_of::<u32>() as isize,
                           indices.as_ptr() as *const _,
                           gl::STATIC_DRAW);

            gl::EnableVertexAttribArray(0);
            gl::VertexAttribPointer(0, 4, gl::FLOAT, gl::FALSE, 4 * size_of::<f32>() as i32,
                                    ptr::null());

            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0);
            gl::BindBuffer(gl::ARRAY_BUFFER, 0);
            gl::BindVertexArray(0);
        }

        QuadRenderer {
            program: program,
            vao: vao,
            vbo: vbo,
            ebo: ebo,
        }
    }

    pub fn render(&self, glyph: &Glyph, x: f32, y: f32) {
        self.program.activate();
        unsafe {
            // set color
            gl::Uniform3f(self.program.u_color, 1., 1., 0.5);
        }

        let rect = get_rect(glyph, x, y);

        let packed = [PackedQuad {
            x_tr: rect.max_x(),
            y_tr: rect.max_y(),
            u_tr: 1.0,
            v_tr: 0.0,
            x_br: rect.max_x(),
            y_br: rect.min_y(),
            u_br: 1.0,
            v_br: 1.0,
            x_bl: rect.min_x(),
            y_bl: rect.min_y(),
            u_bl: 0.0,
            v_bl: 1.0,
            x_tl: rect.min_x(),
            y_tl: rect.max_y(),
            u_tl: 0.0,
            v_tl: 0.0,
        }];

        unsafe {
            bind_mask_texture(glyph.tex_id);
            gl::BindVertexArray(self.vao);

            gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
            gl::BufferSubData(
                gl::ARRAY_BUFFER,
                0,
                (packed.len() * size_of::<PackedQuad>()) as isize,
                packed.as_ptr() as *const _
            );
            gl::BindBuffer(gl::ARRAY_BUFFER, 0);
            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.ebo);

            gl::DrawElements(gl::TRIANGLES, 6, gl::UNSIGNED_INT, ptr::null());
            gl::BindVertexArray(0);
            gl::BindTexture(gl::TEXTURE_2D, 0);
        }

        self.program.deactivate();
    }
}

fn get_rect(glyph: &Glyph, x: f32, y: f32) -> Rect<f32> {
    Rect::new(
        Point2D::new(x, y),
        Size2D::new(glyph.width as f32, glyph.height as f32)
    )
}

fn bind_mask_texture(id: u32) {
    unsafe {
        gl::ActiveTexture(gl::TEXTURE0);
        gl::BindTexture(gl::TEXTURE_2D, id);
    }
}

pub struct ShaderProgram {
    id: GLuint,
    /// projection matrix uniform
    u_projection: GLint,
    /// color uniform
    u_color: GLint,
}

impl ShaderProgram {
    pub fn activate(&self) {
        unsafe {
            gl::UseProgram(self.id);
        }
    }

    pub fn deactivate(&self) {
        unsafe {
            gl::UseProgram(0);
        }
    }

    pub fn new(width: u32, height: u32) -> ShaderProgram {
        let vertex_shader = ShaderProgram::create_vertex_shader();
        let fragment_shader = ShaderProgram::create_fragment_shader();
        let program = ShaderProgram::create_program(vertex_shader, fragment_shader);

        unsafe {
            gl::DeleteShader(vertex_shader);
            gl::DeleteShader(fragment_shader);
        }

        // get uniform locations
        let projection_str = CString::new("projection").unwrap();
        let color_str = CString::new("textColor").unwrap();

        let (projection, color) = unsafe {
            (
                gl::GetUniformLocation(program, projection_str.as_ptr()),
                gl::GetUniformLocation(program, color_str.as_ptr())
            )
        };

        assert!(projection != gl::INVALID_VALUE as i32);
        assert!(projection != gl::INVALID_OPERATION as i32);
        assert!(color != gl::INVALID_VALUE as i32);
        assert!(color != gl::INVALID_OPERATION as i32);

        let shader = ShaderProgram {
            id: program,
            u_projection: projection,
            u_color: color,
        };

        // set projection uniform
        let ortho = cgmath::ortho(0., width as f32, 0., height as f32, -1., 1.);
        let projection: [[f32; 4]; 4] = ortho.into();

        println!("width: {}, height: {}", width, height);

        shader.activate();
        unsafe {
            gl::UniformMatrix4fv(shader.u_projection,
                                 1, gl::FALSE, projection.as_ptr() as *const _);
        }
        shader.deactivate();

        shader
    }

    fn create_program(vertex: GLuint, fragment: GLuint) -> GLuint {

        unsafe {
            let program = gl::CreateProgram();
            gl::AttachShader(program, vertex);
            gl::AttachShader(program, fragment);
            gl::LinkProgram(program);

            let mut success: GLint = 0;
            gl::GetProgramiv(program, gl::LINK_STATUS, &mut success);

            if success != (gl::TRUE as GLint) {
                panic!("failed to link shader program");
            }
            program
        }
    }

    fn create_fragment_shader() -> GLuint {
        unsafe {
            let fragment_shader = gl::CreateShader(gl::FRAGMENT_SHADER);
            let fragment_source = CString::new(TEXT_SHADER_F).unwrap();
            gl::ShaderSource(fragment_shader, 1, &fragment_source.as_ptr(), ptr::null());
            gl::CompileShader(fragment_shader);

            let mut success: GLint = 0;
            gl::GetShaderiv(fragment_shader, gl::COMPILE_STATUS, &mut success);

            if success != (gl::TRUE as GLint) {
                panic!("failed to compiler fragment shader");
            }
            fragment_shader
        }
    }

    fn create_vertex_shader() -> GLuint {
        unsafe {
            let vertex_shader = gl::CreateShader(gl::VERTEX_SHADER);
            let vertex_source = CString::new(TEXT_SHADER_V).unwrap();
            gl::ShaderSource(vertex_shader, 1, &vertex_source.as_ptr(), ptr::null());
            gl::CompileShader(vertex_shader);

            let mut success: GLint = 0;
            gl::GetShaderiv(vertex_shader, gl::COMPILE_STATUS, &mut success);

            if success != (gl::TRUE as GLint) {
                panic!("failed to compiler vertex shader");
            }
            vertex_shader
        }
    }
}

#[allow(dead_code)]
pub struct Glyph {
    tex_id: GLuint,
    top: i32,
    left: i32,
    width: i32,
    height: i32,
}

impl Glyph {
    pub fn new(rasterized: &RasterizedGlyph) -> Glyph {
        let mut id: GLuint = 0;
        unsafe {
            gl::PixelStorei(gl::UNPACK_ALIGNMENT, 1);
            gl::GenTextures(1, &mut id);
            gl::BindTexture(gl::TEXTURE_2D, id);
            gl::TexImage2D(
                gl::TEXTURE_2D,
                0,
                gl::RED as i32,
                rasterized.width as i32,
                rasterized.height as i32,
                0,
                gl::RED,
                gl::UNSIGNED_BYTE,
                rasterized.buf.as_ptr() as *const _
            );

            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);

            gl::BindTexture(gl::TEXTURE_2D, 0);
        }

        Glyph {
            tex_id: id,
            top: rasterized.top as i32,
            width: rasterized.width as i32,
            height: rasterized.height as i32,
            left: rasterized.left as i32,
        }
    }
}
<|endoftext|>


<commit_before>//! Benchmark Fibonacci numbers, F(n) = F(n-1) + F(n-2)
//!
//! Recursion is a horrible way to compute this -- roughly O(2ⁿ).
//!
//! It's potentially interesting for rayon::join, because the splits are
//! unequal.  F(n-1) has roughly twice as much work to do as F(n-2).  The
//! imbalance might make it more likely to leave idle threads ready to steal
//! jobs.  We can also see if there's any effect to having the larger job first
//! or second.
//!
//! We're doing very little real work in each job, so the rayon overhead is
//! going to dominate.  The serial recursive version will likely be faster,
//! unless you have a whole lot of CPUs.  The iterative version reveals the
//! joke.

#![feature(test)]

extern crate rayon;
extern crate test;

use rayon::Configuration;

const INIT_FAILED: &'static str = "Rayon failed to initialize";
const N: u32 = 32;
const FN: u32 = 2178309;

#[bench]
/// Compute the Fibonacci number recursively, without any parallelism.
fn fibonacci_recursive(b: &mut test::Bencher) {

    fn fib(n: u32) -> u32 {
        if n < 2 { return n; }

        fib(n - 1) + fib(n - 2)
    }

    b.iter(|| assert_eq!(fib(test::black_box(N)), FN));
}

#[bench]
/// Compute the Fibonacci number recursively, using rayon::join.
/// The larger branch F(N-1) is computed first.
fn fibonacci_join_1_2(b: &mut test::Bencher) {
    rayon::initialize(Configuration::new())
                     .expect(INIT_FAILED);

    fn fib(n: u32) -> u32 {
        if n < 2 { return n; }

        let (a, b) = rayon::join(
            || fib(n - 1),
            || fib(n - 2));
        a + b
    }

    b.iter(|| assert_eq!(fib(test::black_box(N)), FN));
}

#[bench]
/// Compute the Fibonacci number recursively, using rayon::join.
/// The smaller branch F(N-2) is computed first.
fn fibonacci_join_2_1(b: &mut test::Bencher) {
    rayon::initialize(Configuration::new())
                     .expect(INIT_FAILED);

    fn fib(n: u32) -> u32 {
        if n < 2 { return n; }

        let (a, b) = rayon::join(
            || fib(n - 2),
            || fib(n - 1));
        a + b
    }

    b.iter(|| assert_eq!(fib(test::black_box(N)), FN));
}

#[bench]
/// Compute the Fibonacci number iteratively, just to show how silly the others
/// are.  Parallelism can't make up for a bad choice of algorithm.
fn fibonacci_iterative(b: &mut test::Bencher) {

    fn fib(n: u32) -> u32 {
        let mut a = 0;
        let mut b = 1;
        for _ in 0..n {
            let c = a + b;
            a = b;
            b = c;
        }
        a
    }

    b.iter(|| assert_eq!(fib(test::black_box(N)), FN));
}
<commit_msg>remove unused attribute<commit_after>//! Benchmark Fibonacci numbers, F(n) = F(n-1) + F(n-2)
//!
//! Recursion is a horrible way to compute this -- roughly O(2ⁿ).
//!
//! It's potentially interesting for rayon::join, because the splits are
//! unequal.  F(n-1) has roughly twice as much work to do as F(n-2).  The
//! imbalance might make it more likely to leave idle threads ready to steal
//! jobs.  We can also see if there's any effect to having the larger job first
//! or second.
//!
//! We're doing very little real work in each job, so the rayon overhead is
//! going to dominate.  The serial recursive version will likely be faster,
//! unless you have a whole lot of CPUs.  The iterative version reveals the
//! joke.

extern crate rayon;
extern crate test;

use rayon::Configuration;

const INIT_FAILED: &'static str = "Rayon failed to initialize";
const N: u32 = 32;
const FN: u32 = 2178309;

#[bench]
/// Compute the Fibonacci number recursively, without any parallelism.
fn fibonacci_recursive(b: &mut test::Bencher) {

    fn fib(n: u32) -> u32 {
        if n < 2 { return n; }

        fib(n - 1) + fib(n - 2)
    }

    b.iter(|| assert_eq!(fib(test::black_box(N)), FN));
}

#[bench]
/// Compute the Fibonacci number recursively, using rayon::join.
/// The larger branch F(N-1) is computed first.
fn fibonacci_join_1_2(b: &mut test::Bencher) {
    rayon::initialize(Configuration::new())
                     .expect(INIT_FAILED);

    fn fib(n: u32) -> u32 {
        if n < 2 { return n; }

        let (a, b) = rayon::join(
            || fib(n - 1),
            || fib(n - 2));
        a + b
    }

    b.iter(|| assert_eq!(fib(test::black_box(N)), FN));
}

#[bench]
/// Compute the Fibonacci number recursively, using rayon::join.
/// The smaller branch F(N-2) is computed first.
fn fibonacci_join_2_1(b: &mut test::Bencher) {
    rayon::initialize(Configuration::new())
                     .expect(INIT_FAILED);

    fn fib(n: u32) -> u32 {
        if n < 2 { return n; }

        let (a, b) = rayon::join(
            || fib(n - 2),
            || fib(n - 1));
        a + b
    }

    b.iter(|| assert_eq!(fib(test::black_box(N)), FN));
}

#[bench]
/// Compute the Fibonacci number iteratively, just to show how silly the others
/// are.  Parallelism can't make up for a bad choice of algorithm.
fn fibonacci_iterative(b: &mut test::Bencher) {

    fn fib(n: u32) -> u32 {
        let mut a = 0;
        let mut b = 1;
        for _ in 0..n {
            let c = a + b;
            a = b;
            b = c;
        }
        a
    }

    b.iter(|| assert_eq!(fib(test::black_box(N)), FN));
}
<|endoftext|>