<commit_before>use std;
use meow;

fn BM(haystack: str, needle: str) -> [uint] {
   str::boyer_moore_search(haystack, needle,
                           str::len(haystack),
                           0u, str::len(haystack))
}

fn simple(haystack: str, needle: str) -> [uint] {
   str::simple_search(haystack, needle,
                      str::len(haystack),
                      0u, str::len(haystack))
}

fn compareHN(hlen: uint, nlen: uint) -> float {
   // some strings to test
   let generator = rand::rng();
   let needle   = generator.gen_str(nlen);
   let haystack = generator.gen_str(hlen);

   // run each
   //let sT  = meow::measure_time({|| sim_found = simple(haystack, needle);});
   //let bmT = meow::measure_time({|| bm_found  = BM(haystack, needle);});
   let sT  = meow::measure_time({|| simple(haystack, needle)});
   let bmT = meow::measure_time({|| BM(haystack, needle)});

   // they've gotta be the same
   //assert sim_found == bm_found;

   ret bmT as float / sT as float;
}

fn main() {
/*
   let bible = meow::bible();
   //let phrase = "And leik, dont think ur all hot soup cuz you just read the FAQ.";
   let phrase = "And leik, dont think ur all hot soup cuz you just read the BANANAS.";
   let phrase2 = "x-ray-banana";

   meow::time("c simple", {|| simple(bible, phrase)});
   meow::time("c BM", {||    BM(bible, phrase)});

   let yy = "superxpalidocious exxpeealidocioussuperxpalidocious exxpeealidocioussuperxpalidocious exxpeealidocious";
   meow::time("c1 simple", {|| simple(bible, yy)});
   meow::time("c1 BM", {||    BM(bible, yy)});

   let mut ii = 0u;
   let N = 40u;
   let mut bibleN = "";
   str::reserve(bibleN, N * str::len(bibleN) + 1u);
   while ii < N {
      bibleN += bible;
      ii += 1u;
   }

   meow::time("d simple", {|| simple(bibleN, phrase2)});
   meow::time("d BM", {||    BM(bibleN, phrase2)});
*/

/*
   let loremipsum = "
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris laoreet consequat fringilla. Quisque venenatis lacinia ipsum non rhoncus. Donec adipiscing fringilla erat, a pretium purus rhoncus quis. Nunc rhoncus dui at ipsum bibendum tincidunt. Etiam eu lorem nulla. Nulla id est id augue blandit vestibulum. Nullam eleifend gravida feugiat. Aliquam vitae urna arcu. Ut sed enim dui, a suscipit sapien.

Ut sollicitudin, metus id malesuada dapibus, quam velit ultrices nibh, at feugiat diam tellus eget risus. Vestibulum in ultrices enim. Nulla at est molestie augue hendrerit tempor sed in purus. Mauris non lorem libero, id faucibus odio. Proin feugiat magna id diam laoreet eu dapibus sapien eleifend. Nunc imperdiet auctor hendrerit. Curabitur porta tempus quam, vel scelerisque elit feugiat ac. Vestibulum feugiat bibendum massa in dapibus. Quisque lacinia porttitor turpis et auctor. Ut quis tortor vitae ligula faucibus euismod nec eu risus. Nullam blandit, risus at consectetur dapibus, velit nisl tincidunt tortor, sed varius risus neque sit amet purus. In diam nisl, facilisis tristique convallis sit amet, posuere congue augue. Vestibulum malesuada, tellus vitae mattis laoreet, nulla felis posuere libero, et blandit eros erat at lacus. Morbi id placerat magna. Nulla lacus magna, gravida sit amet elementum et, posuere nec sapien. Maecenas vitae felis magna, fringilla facilisis massa.

Ut porta, ligula id blandit volutpat, felis sapien ornare sapien, a auctor felis nunc in risus. Etiam in erat at tellus rutrum euismod quis at quam. Proin massa mauris, auctor in tempor eu, cursus quis metus. Suspendisse et dolor quam. Nam id neque eget lorem interdum ultricies. Phasellus aliquet facilisis tortor ac pellentesque. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse sed porta purus. Donec consectetur imperdiet tortor et sagittis. Ut pretium vulputate tortor eget ullamcorper. Nullam a urna sollicitudin quam mollis fermentum eu id enim. Mauris pharetra blandit ultricies. In ligula justo, rhoncus et tempus vitae, rutrum non neque.

In accumsan pulvinar lorem sed sollicitudin. Donec justo sem, aliquet at posuere ut, tempus at est. Quisque mattis scelerisque felis ac semper. Quisque nec tristique orci. Donec id diam ut ipsum auctor hendrerit non non sem. Vivamus non erat eros, at vulputate dolor. Duis vehicula, neque sed rhoncus ornare, ante est placerat erat, non luctus justo libero quis mauris. Pellentesque sollicitudin dignissim faucibus. Nunc arcu urna, hendrerit at sagittis nec, dapibus eu leo. Sed eget libero nec risus aliquet hendrerit ullamcorper vel sem. Vestibulum eleifend elit sed tellus tempor elementum. Maecenas eu nibh quis tortor pretium ullamcorper id vel nibh. Pellentesque viverra, nulla vitae condimentum pretium, enim nisl euismod odio, eget vulputate velit justo in lorem.

Nunc eget leo ipsum. Nulla facilisi. Nam adipiscing justo id nisl aliquam at posuere nulla pharetra. Pellentesque fringilla fringilla placerat. Nam pulvinar vehicula augue, a vestibulum turpis rutrum eu. Curabitur semper viverra elit id ultricies. Nunc nibh lacus, congue at imperdiet eget, lacinia at lorem. Aliquam erat volutpat. Pellentesque malesuada ultrices arcu, eu dignissim nisi consectetur at. Nam tristique justo molestie lorem pellentesque vel consectetur augue hendrerit.
";

   meow::time("lorem ipsum (400) in bible (simple)",
              {|| simple(bible, str::slice(loremipsum, 0u, 400u))});
   meow::time("lorem ipsum (400) in bible (BM)   ",
              {||    BM(bible, str::slice(loremipsum, 0u, 400u))});

   let mut ii = 0u;
   let N = 40u;
   let mut bibleN = "";
   str::reserve(bibleN, N * str::len(bibleN) + 1u);
   while ii < N {
      bibleN += bible;
      ii += 1u;
   }

   meow::time("lorem ipsum (100) in bible x40 (simple)",
              {|| simple(bibleN, str::slice(loremipsum, 0u, 100u))});
   meow::time("lorem ipsum (100) in bible x40 (BM)   ",
              {||    BM(bibleN, str::slice(loremipsum, 0u, 100u))});

   meow::time("lorem ipsum (400) in bible x40 (simple)",
              {|| simple(bibleN, str::slice(loremipsum, 0u, 400u))});
   meow::time("lorem ipsum (400) in bible x40 (BM)   ",
              {||    BM(bibleN, str::slice(loremipsum, 0u, 400u))});

   let mut ii = 0u;
   let N = 160u;
   let mut bibleN = "";
   str::reserve(bibleN, N * str::len(bibleN) + 1u);
   while ii < N {
      bibleN += bible;
      ii += 1u;
   }

   meow::time("lorem ipsum (100) in bible x160 (simple)",
              {|| simple(bibleN, str::slice(loremipsum, 0u, 100u))});
   meow::time("lorem ipsum (100) in bible x160 (BM)   ",
              {||    BM(bibleN, str::slice(loremipsum, 0u, 100u))});

   meow::time("lorem ipsum (400) in bible x160 (simple)",
              {|| simple(bibleN, str::slice(loremipsum, 0u, 400u))});
   meow::time("lorem ipsum (400) in bible x160 (BM)   ",
              {||    BM(bibleN, str::slice(loremipsum, 0u, 400u))});

   let mut ii = 0u;
   let N = 260u;
   let mut bibleN = "";
   str::reserve(bibleN, N * str::len(bibleN) + 1u);
   while ii < N {
      bibleN += bible;
      ii += 1u;
   }

   meow::time("lorem ipsum (100) in bible x260 (simple)",
              {|| simple(bibleN, str::slice(loremipsum, 0u, 100u))});
   meow::time("lorem ipsum (100) in bible x260 (BM)   ",
              {||    BM(bibleN, str::slice(loremipsum, 0u, 100u))});

   meow::time("lorem ipsum (400) in bible x260 (simple)",
              {|| simple(bibleN, str::slice(loremipsum, 0u, 400u))});
   meow::time("lorem ipsum (400) in bible x260 (BM)   ",
              {||    BM(bibleN, str::slice(loremipsum, 0u, 400u))});

*/

//   meow::time("lorem ipsum ^2 (simple)", {|| BM(loremipsum, loremipsum)} );
//   meow::time("lorem ipsum ^2 (BM)", {|| BM(loremipsum, loremipsum)} );

   // 2D range
   let (num_n, num_h) = (10u, 20u);
   let (mult_n, mult_h) = (100u, 1000u);
   let row1 = vec::to_mut(vec::from_elem(num_h, 1.0f));
   let result = vec::to_mut(vec::from_elem(num_n, row1));
   let mut nn = 0u;
   while nn < num_n {
      let mut hh = 0u;
      while hh < num_h {
         // save a grid of ratio of time for BM / simple search
         result[nn][hh] = compareHN(1u+hh*mult_h, 1u+nn*mult_n);

         hh += 1u;
      }
      nn += 1u;
   }

   let matlab_data_2d = fn@(data: [mut [mut float]]) -> (str,str,str) {
      // captured:
      //let mult_h, mult_n;

      let xxlim = vec::len(data);
      let yylim = vec::len(data[0]);

      let mut res = "";
      let mut xs = "";
      let mut ys = "";

      // Y
      let mut yy = 0u;
      while yy < yylim {
         if yy != 0u {
            res += "; ";
            xs += ", ";
         }

         // X
         let mut xx = 0u;
         while xx < xxlim {
            if xx != 0u {
               res += ", ";
               if yy == 0u {
                  ys += ", ";
               }
            }

            // data
            res += #fmt("%f", data[xx][yy]);

            if yy == 0u {
               ys += #fmt("%u", 1u + mult_n * xx);
            }
            xx += 1u;
         }

         xs += #fmt("%u", 1u + mult_h * yy);
         yy += 1u;
      }

      ret (xs, ys, res);
   };

   io::println("######################################################");
   io::println("### paste into Octave or Matlab... ###################");

   // output to octave/matlab
   let (xs, ys, ratio) = matlab_data_2d(result);
   io::println("ratio     = [" + ratio + "];");
   io::println("haystacks = [" + ys + "];");
   io::println("needles   = [" + xs + "];");

   io::println("contourf(haystacks, needles, ratio, [0, 1, 2, 3]);");
   io::println("xlabel('needle size');");
   io::println("ylabel('haystack size');");
   io::println("title('Boyer-Moore time / basic search time');");
   io::println("xlim([1 901]);");
   io::println("ylim([1 19001]);");
   io::println("colorbar;");
   io::println("");
   io::println("print('comparison.svg', '-dSVG');");

   io::println("######################################################");
}

<commit_msg>i prefer pink and blue...<commit_after>use std;
use meow;

fn BM(haystack: str, needle: str) -> [uint] {
   str::boyer_moore_search(haystack, needle,
                           str::len(haystack),
                           0u, str::len(haystack))
}

fn simple(haystack: str, needle: str) -> [uint] {
   str::simple_search(haystack, needle,
                      str::len(haystack),
                      0u, str::len(haystack))
}

fn compareHN(hlen: uint, nlen: uint) -> float {
   // some strings to test
   let generator = rand::rng();
   let needle   = generator.gen_str(nlen);
   let haystack = generator.gen_str(hlen);

   // run each
   //let sT  = meow::measure_time({|| sim_found = simple(haystack, needle);});
   //let bmT = meow::measure_time({|| bm_found  = BM(haystack, needle);});
   let sT  = meow::measure_time({|| simple(haystack, needle)});
   let bmT = meow::measure_time({|| BM(haystack, needle)});

   // they've gotta be the same
   //assert sim_found == bm_found;

   ret bmT as float / sT as float;
}

fn main() {
/*
   let bible = meow::bible();
   //let phrase = "And leik, dont think ur all hot soup cuz you just read the FAQ.";
   let phrase = "And leik, dont think ur all hot soup cuz you just read the BANANAS.";
   let phrase2 = "x-ray-banana";

   meow::time("c simple", {|| simple(bible, phrase)});
   meow::time("c BM", {||    BM(bible, phrase)});

   let yy = "superxpalidocious exxpeealidocioussuperxpalidocious exxpeealidocioussuperxpalidocious exxpeealidocious";
   meow::time("c1 simple", {|| simple(bible, yy)});
   meow::time("c1 BM", {||    BM(bible, yy)});

   let mut ii = 0u;
   let N = 40u;
   let mut bibleN = "";
   str::reserve(bibleN, N * str::len(bibleN) + 1u);
   while ii < N {
      bibleN += bible;
      ii += 1u;
   }

   meow::time("d simple", {|| simple(bibleN, phrase2)});
   meow::time("d BM", {||    BM(bibleN, phrase2)});
*/

/*
   let loremipsum = "
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris laoreet consequat fringilla. Quisque venenatis lacinia ipsum non rhoncus. Donec adipiscing fringilla erat, a pretium purus rhoncus quis. Nunc rhoncus dui at ipsum bibendum tincidunt. Etiam eu lorem nulla. Nulla id est id augue blandit vestibulum. Nullam eleifend gravida feugiat. Aliquam vitae urna arcu. Ut sed enim dui, a suscipit sapien.

Ut sollicitudin, metus id malesuada dapibus, quam velit ultrices nibh, at feugiat diam tellus eget risus. Vestibulum in ultrices enim. Nulla at est molestie augue hendrerit tempor sed in purus. Mauris non lorem libero, id faucibus odio. Proin feugiat magna id diam laoreet eu dapibus sapien eleifend. Nunc imperdiet auctor hendrerit. Curabitur porta tempus quam, vel scelerisque elit feugiat ac. Vestibulum feugiat bibendum massa in dapibus. Quisque lacinia porttitor turpis et auctor. Ut quis tortor vitae ligula faucibus euismod nec eu risus. Nullam blandit, risus at consectetur dapibus, velit nisl tincidunt tortor, sed varius risus neque sit amet purus. In diam nisl, facilisis tristique convallis sit amet, posuere congue augue. Vestibulum malesuada, tellus vitae mattis laoreet, nulla felis posuere libero, et blandit eros erat at lacus. Morbi id placerat magna. Nulla lacus magna, gravida sit amet elementum et, posuere nec sapien. Maecenas vitae felis magna, fringilla facilisis massa.

Ut porta, ligula id blandit volutpat, felis sapien ornare sapien, a auctor felis nunc in risus. Etiam in erat at tellus rutrum euismod quis at quam. Proin massa mauris, auctor in tempor eu, cursus quis metus. Suspendisse et dolor quam. Nam id neque eget lorem interdum ultricies. Phasellus aliquet facilisis tortor ac pellentesque. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse sed porta purus. Donec consectetur imperdiet tortor et sagittis. Ut pretium vulputate tortor eget ullamcorper. Nullam a urna sollicitudin quam mollis fermentum eu id enim. Mauris pharetra blandit ultricies. In ligula justo, rhoncus et tempus vitae, rutrum non neque.

In accumsan pulvinar lorem sed sollicitudin. Donec justo sem, aliquet at posuere ut, tempus at est. Quisque mattis scelerisque felis ac semper. Quisque nec tristique orci. Donec id diam ut ipsum auctor hendrerit non non sem. Vivamus non erat eros, at vulputate dolor. Duis vehicula, neque sed rhoncus ornare, ante est placerat erat, non luctus justo libero quis mauris. Pellentesque sollicitudin dignissim faucibus. Nunc arcu urna, hendrerit at sagittis nec, dapibus eu leo. Sed eget libero nec risus aliquet hendrerit ullamcorper vel sem. Vestibulum eleifend elit sed tellus tempor elementum. Maecenas eu nibh quis tortor pretium ullamcorper id vel nibh. Pellentesque viverra, nulla vitae condimentum pretium, enim nisl euismod odio, eget vulputate velit justo in lorem.

Nunc eget leo ipsum. Nulla facilisi. Nam adipiscing justo id nisl aliquam at posuere nulla pharetra. Pellentesque fringilla fringilla placerat. Nam pulvinar vehicula augue, a vestibulum turpis rutrum eu. Curabitur semper viverra elit id ultricies. Nunc nibh lacus, congue at imperdiet eget, lacinia at lorem. Aliquam erat volutpat. Pellentesque malesuada ultrices arcu, eu dignissim nisi consectetur at. Nam tristique justo molestie lorem pellentesque vel consectetur augue hendrerit.
";

   meow::time("lorem ipsum (400) in bible (simple)",
              {|| simple(bible, str::slice(loremipsum, 0u, 400u))});
   meow::time("lorem ipsum (400) in bible (BM)   ",
              {||    BM(bible, str::slice(loremipsum, 0u, 400u))});

   let mut ii = 0u;
   let N = 40u;
   let mut bibleN = "";
   str::reserve(bibleN, N * str::len(bibleN) + 1u);
   while ii < N {
      bibleN += bible;
      ii += 1u;
   }

   meow::time("lorem ipsum (100) in bible x40 (simple)",
              {|| simple(bibleN, str::slice(loremipsum, 0u, 100u))});
   meow::time("lorem ipsum (100) in bible x40 (BM)   ",
              {||    BM(bibleN, str::slice(loremipsum, 0u, 100u))});

   meow::time("lorem ipsum (400) in bible x40 (simple)",
              {|| simple(bibleN, str::slice(loremipsum, 0u, 400u))});
   meow::time("lorem ipsum (400) in bible x40 (BM)   ",
              {||    BM(bibleN, str::slice(loremipsum, 0u, 400u))});

   let mut ii = 0u;
   let N = 160u;
   let mut bibleN = "";
   str::reserve(bibleN, N * str::len(bibleN) + 1u);
   while ii < N {
      bibleN += bible;
      ii += 1u;
   }

   meow::time("lorem ipsum (100) in bible x160 (simple)",
              {|| simple(bibleN, str::slice(loremipsum, 0u, 100u))});
   meow::time("lorem ipsum (100) in bible x160 (BM)   ",
              {||    BM(bibleN, str::slice(loremipsum, 0u, 100u))});

   meow::time("lorem ipsum (400) in bible x160 (simple)",
              {|| simple(bibleN, str::slice(loremipsum, 0u, 400u))});
   meow::time("lorem ipsum (400) in bible x160 (BM)   ",
              {||    BM(bibleN, str::slice(loremipsum, 0u, 400u))});

   let mut ii = 0u;
   let N = 260u;
   let mut bibleN = "";
   str::reserve(bibleN, N * str::len(bibleN) + 1u);
   while ii < N {
      bibleN += bible;
      ii += 1u;
   }

   meow::time("lorem ipsum (100) in bible x260 (simple)",
              {|| simple(bibleN, str::slice(loremipsum, 0u, 100u))});
   meow::time("lorem ipsum (100) in bible x260 (BM)   ",
              {||    BM(bibleN, str::slice(loremipsum, 0u, 100u))});

   meow::time("lorem ipsum (400) in bible x260 (simple)",
              {|| simple(bibleN, str::slice(loremipsum, 0u, 400u))});
   meow::time("lorem ipsum (400) in bible x260 (BM)   ",
              {||    BM(bibleN, str::slice(loremipsum, 0u, 400u))});

*/

//   meow::time("lorem ipsum ^2 (simple)", {|| BM(loremipsum, loremipsum)} );
//   meow::time("lorem ipsum ^2 (BM)", {|| BM(loremipsum, loremipsum)} );

   // 2D range
   let (num_n, num_h) = (10u, 20u);
   let (mult_n, mult_h) = (100u, 1000u);
   let row1 = vec::to_mut(vec::from_elem(num_h, 1.0f));
   let result = vec::to_mut(vec::from_elem(num_n, row1));
   let mut nn = 0u;
   while nn < num_n {
      let mut hh = 0u;
      while hh < num_h {
         // save a grid of ratio of time for BM / simple search
         result[nn][hh] = compareHN(1u+hh*mult_h, 1u+nn*mult_n);

         hh += 1u;
      }
      nn += 1u;
   }

   let matlab_data_2d = fn@(data: [mut [mut float]]) -> (str,str,str) {
      // captured:
      //let mult_h, mult_n;

      let xxlim = vec::len(data);
      let yylim = vec::len(data[0]);

      let mut res = "";
      let mut xs = "";
      let mut ys = "";

      // Y
      let mut yy = 0u;
      while yy < yylim {
         if yy != 0u {
            res += "; ";
            xs += ", ";
         }

         // X
         let mut xx = 0u;
         while xx < xxlim {
            if xx != 0u {
               res += ", ";
               if yy == 0u {
                  ys += ", ";
               }
            }

            // data
            res += #fmt("%f", data[xx][yy]);

            if yy == 0u {
               ys += #fmt("%u", 1u + mult_n * xx);
            }
            xx += 1u;
         }

         xs += #fmt("%u", 1u + mult_h * yy);
         yy += 1u;
      }

      ret (xs, ys, res);
   };

   io::println("######################################################");
   io::println("### paste into Octave or Matlab... ###################");

   // output to octave/matlab
   let (xs, ys, ratio) = matlab_data_2d(result);
   io::println("ratio     = [" + ratio + "];");
   io::println("haystacks = [" + ys + "];");
   io::println("needles   = [" + xs + "];");

   io::println("contourf(haystacks, needles, ratio, [0, 1, 2, 3]);");
   io::println("xlabel('needle size');");
   io::println("ylabel('haystack size');");
   io::println("title('Boyer-Moore time / basic search time');");
   io::println("xlim([1 901]);");
   io::println("ylim([1 19001]);");
   io::println("colormap('cool');");
   io::println("colorbar;");
   io::println("");
   io::println("print('comparison.svg', '-dSVG');");

   io::println("######################################################");
}

<|endoftext|>


<commit_before>use std::error;

/// Functionality for sending authenticated and unauthenticated requests to Slack via HTTP.
///
/// Should be implemented for clients to send requests to Slack.
pub trait SlackWebRequestSender {
    type Error: error::Error;

    /// Make an API call to Slack. Takes a map of parameters that get appended to the request as query
    /// params.
    fn send(&self, method: &str, params: &[(&str, &str)]) -> Result<String, Self::Error>;
}

#[cfg(feature = "reqwest")]
mod reqwest_support {
    pub extern crate reqwest;

    use std::io::Read;

    use super::SlackWebRequestSender;

    impl SlackWebRequestSender for reqwest::Client {
        type Error = reqwest::Error;

        fn send(&self, method_url: &str, params: &[(&str, &str)]) -> Result<String, Self::Error> {
            let mut url = reqwest::Url::parse(&method_url).expect("Unable to parse url");

            url.query_pairs_mut().extend_pairs(params);

            let mut response = self.get(url).send()?;
            let mut res_str = String::new();
            response.read_to_string(&mut res_str).map_err(reqwest::HyperError::from)?;

            Ok(res_str)
        }
    }
}

#[cfg(feature = "reqwest")]
pub use self::reqwest_support::*;
<commit_msg>add default_client function, remove export of reqwest<commit_after>use std::error;

/// Functionality for sending authenticated and unauthenticated requests to Slack via HTTP.
///
/// Should be implemented for clients to send requests to Slack.
pub trait SlackWebRequestSender {
    type Error: error::Error;

    /// Make an API call to Slack. Takes a map of parameters that get appended to the request as query
    /// params.
    fn send(&self, method: &str, params: &[(&str, &str)]) -> Result<String, Self::Error>;
}

#[cfg(feature = "reqwest")]
mod reqwest_support {
    extern crate reqwest;
    pub use self::reqwest::Client;
    pub use self::reqwest::Error;

    use std::io::Read;

    use super::SlackWebRequestSender;

    impl SlackWebRequestSender for reqwest::Client {
        type Error = reqwest::Error;

        fn send(&self, method_url: &str, params: &[(&str, &str)]) -> Result<String, Self::Error> {
            let mut url = reqwest::Url::parse(&method_url).expect("Unable to parse url");

            url.query_pairs_mut().extend_pairs(params);

            let mut response = self.get(url).send()?;
            let mut res_str = String::new();
            response.read_to_string(&mut res_str).map_err(reqwest::HyperError::from)?;

            Ok(res_str)
        }
    }

    pub fn default_client() -> Result<reqwest::Client, reqwest::Error> {
        reqwest::Client::new()
    }
}

#[cfg(feature = "reqwest")]
pub use self::reqwest_support::*;
<|endoftext|>


<commit_before>// Copyright 2015 The tiny-http Contributors
//
// 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 common::{Header, HTTPVersion, StatusCode};

use std::ascii::AsciiExt;
use std::cmp::Ordering;
use std::sync::mpsc::Receiver;

use std::io::{self, Read, Write, Cursor};
use std::io::Result as IoResult;

use std::fs::File;

use std::str::FromStr;

/// Object representing an HTTP response whose purpose is to be given to a `Request`.
///
/// Some headers cannot be changed. Trying to define the value
/// of one of these will have no effect:
///
///  - `Accept-Ranges`
///  - `Connection`
///  - `Content-Range`
///  - `Trailer`
///  - `Transfer-Encoding`
///  - `Upgrade`
///
/// Some headers have special behaviors:
///
///  - `Content-Encoding`: If you define this header, the library
///     will assume that the data from the `Read` object has the specified encoding
///     and will just pass-through.
///
///  - `Content-Length`: The length of the data should be set manually
///     using the `Reponse` object's API. Attempting to set the value of this
///     header will be equivalent to modifying the size of the data but the header
///     itself may not be present in the final result.
///
pub struct Response<R> where R: Read {
    reader: R,
    status_code: StatusCode,
    headers: Vec<Header>,
    data_length: Option<usize>,
}

/// A `Response` without a template parameter.
pub type ResponseBox = Response<Box<Read + Send>>;

/// Transfer encoding to use when sending the message.
/// Note that only *supported* encoding are listed here.
enum TransferEncoding {
    Identity,
    Chunked,
}

impl FromStr for TransferEncoding {
    type Err = ();

    fn from_str(input: &str) -> Result<TransferEncoding, ()> {
        if input.eq_ignore_ascii_case("identity") {
            Ok(TransferEncoding::Identity)
        } else if input.eq_ignore_ascii_case("chunked") {
            Ok(TransferEncoding::Chunked)
        } else {
            Err(())
        }
    }
}

/// Builds a Date: header with the current date.
fn build_date_header() -> Header {
    // FIXME: right date
    Header::from_bytes(&b"Date"[..], &b"Wed, 15 Nov 1995 06:25:24 GMT"[..]).unwrap()
}

fn write_message_header<W>(mut writer: W, http_version: &HTTPVersion,
                           status_code: &StatusCode, headers: &[Header])
                           -> IoResult<()> where W: Write
{
    // writing status line
    try!(write!(&mut writer, "HTTP/{}.{} {} {}\r\n",
        http_version.0,
        http_version.1,
        status_code.0,
        status_code.get_default_reason_phrase()
    ));

    // writing headers
    for header in headers.iter() {
        try!(writer.write_all(header.field.as_str().as_ref()));
        try!(write!(&mut writer, ": "));
        try!(writer.write_all(header.value.as_ref().as_ref()));
        try!(write!(&mut writer, "\r\n"));
    }

    // separator between header and data
    try!(write!(&mut writer, "\r\n"));

    Ok(())
}

fn choose_transfer_encoding(request_headers: &[Header], http_version: &HTTPVersion,
                            entity_length: &Option<usize>, has_additional_headers: bool)
    -> TransferEncoding
{
    use util;

    // HTTP 1.0 doesn't support other encoding
    if *http_version <= (1, 0) {
        return TransferEncoding::Identity;
    }

    // parsing the request's TE header
    let user_request = request_headers.iter()
        // finding TE
        .find(|h| h.field.equiv(&"TE"))

        // getting its value
        .map(|h| h.value.clone())

        // getting the corresponding TransferEncoding
        .and_then(|value| {
            // getting list of requested elements
            let mut parse = util::parse_header_value(value.as_str());     // TODO: remove conversion

            // sorting elements by most priority
            parse.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));

            // trying to parse each requested encoding
            for value in parse.iter() {
                // q=0 are ignored
                if value.1 <= 0.0 { continue }

                match <TransferEncoding as FromStr>::from_str(value.0) {
                    Ok(te) => return Some(te),
                    _ => ()     // unrecognized/unsupported encoding
                };
            }

            // encoding not found
            None
        });

    //
    if user_request.is_some() {
        return user_request.unwrap();
    }

    // if we have additional headers, using chunked
    if has_additional_headers {
        return TransferEncoding::Chunked;
    }

    // if we don't have a Content-Length, or if the Content-Length is too big, using chunks writer
    let chunks_threshold = 32768;
    if entity_length.as_ref().map_or(true, |val| *val >= chunks_threshold) {
        return TransferEncoding::Chunked;
    }

    // Identity by default
    TransferEncoding::Identity
}

impl<R> Response<R> where R: Read {
    /// Creates a new Response object.
    ///
    /// The `additional_headers` argument is a receiver that
    ///  may provide headers even after the response has been sent.
    ///
    /// All the other arguments are straight-forward.
    pub fn new(status_code: StatusCode, headers: Vec<Header>,
               data: R, data_length: Option<usize>,
               additional_headers: Option<Receiver<Header>>)
                -> Response<R>
    {
        let mut response = Response {
            reader: data,
            status_code: status_code,
            headers: Vec::with_capacity(16),
            data_length: data_length,
        };

        for h in headers {
            response.add_header(h)
        }

        // dummy implementation
        if let Some(additional_headers) = additional_headers {
            for h in additional_headers.iter() {
                response.add_header(h)
            }
        }

        response
    }

    /// Adds a header to the list.
    /// Does all the checks.
    pub fn add_header<H>(&mut self, header: H) where H: Into<Header> {
        let header = header.into();

        // ignoring forbidden headers
        if header.field.equiv(&"Accept-Ranges") ||
           header.field.equiv(&"Connection") ||
           header.field.equiv(&"Content-Range") ||
           header.field.equiv(&"Trailer") ||
           header.field.equiv(&"Transfer-Encoding") ||
           header.field.equiv(&"Upgrade")
        {
            return;
        }

        // if the header is Content-Length, setting the data length
        if header.field.equiv(&"Content-Length") {
            match <usize as FromStr>::from_str(header.value.as_str()) {
                Ok(val) => self.data_length = Some(val),
                Err(_) => ()      // wrong value for content-length
            };

            return;
        }

        self.headers.push(header);
    }

    /// Returns the same request, but with an additional header.
    ///
    /// Some headers cannot be modified and some other have a
    ///  special behavior. See the documentation above.
    #[inline]
    pub fn with_header<H>(mut self, header: H) -> Response<R> where H: Into<Header> {
        self.add_header(header.into());
        self
    }

    /// Returns the same request, but with a different status code.
    #[inline]
    pub fn with_status_code<S>(mut self, code: S) -> Response<R> where S: Into<StatusCode> {
        self.status_code = code.into();
        self
    }

    /// Returns the same request, but with different data.
    pub fn with_data<S>(self, reader: S, data_length: Option<usize>) -> Response<S> where S: Read {
        Response {
            reader: reader,
            headers: self.headers,
            status_code: self.status_code,
            data_length: data_length,
        }
    }

    /// Prints the HTTP response to a writer.
    ///
    /// This function is the one used to send the response to the client's socket.
    /// Therefore you shouldn't expect anything pretty-printed or even readable.
    ///
    /// The HTTP version and headers passed as arguments are used to
    ///  decide which features (most notably, encoding) to use.
    ///
    /// Note: does not flush the writer.
    pub fn raw_print<W: Write>(mut self, mut writer: W, http_version: HTTPVersion,
                               request_headers: &[Header], do_not_send_body: bool,
                               upgrade: Option<&str>)
                               -> IoResult<()>
    {
        let mut transfer_encoding = Some(choose_transfer_encoding(request_headers,
                                    &http_version, &self.data_length, false /* TODO */));

        // add `Date` if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Date")).is_none() {
            self.headers.insert(0, build_date_header());
        }

        // add `Server` if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Server")).is_none() {
            self.headers.insert(0,
                Header::from_bytes(&b"Server"[..], &b"tiny-http (Rust)"[..]).unwrap()
            );
        }

        // handling upgrade
        if let Some(upgrade) = upgrade {
            self.headers.insert(0, Header::from_bytes(&b"Upgrade"[..], upgrade.as_bytes()).unwrap());
            self.headers.insert(0, Header::from_bytes(&b"Connection"[..], &b"upgrade"[..]).unwrap());
            transfer_encoding = None;
        }

        // checking whether to ignore the body of the response
        let do_not_send_body = do_not_send_body ||
            match self.status_code.0 {
                // sattus code 1xx, 204 and 304 MUST not include a body
                100...199 | 204 | 304 => true,
                _ => false
            };

        // preparing headers for transfer
        match transfer_encoding {
            Some(TransferEncoding::Chunked) => {
                self.headers.push(
                    Header::from_bytes(&b"Transfer-Encoding"[..], &b"chunked"[..]).unwrap()
                )
            },

            Some(TransferEncoding::Identity) => {
                assert!(self.data_length.is_some());
                let data_length = self.data_length.unwrap();

                self.headers.push(
                    Header::from_bytes(&b"Content-Length"[..], format!("{}", data_length).as_bytes()).unwrap()
                )
            },

            _ => ()
        };

        // sending headers
        try!(write_message_header(writer.by_ref(), &http_version,
            &self.status_code, &self.headers));

        // sending the body
        if !do_not_send_body {
            match transfer_encoding {

                Some(TransferEncoding::Chunked) => {
                    use chunked_transfer::Encoder;

                    let mut writer = Encoder::new(writer);
                    try!(io::copy(&mut self.reader, &mut writer));
                },

                Some(TransferEncoding::Identity) => {
                    use util::EqualReader;

                    assert!(self.data_length.is_some());
                    let data_length = self.data_length.unwrap();

                    if data_length >= 1 {
                        let (mut equ_reader, _) =
                            EqualReader::new(self.reader.by_ref(), data_length);
                        try!(io::copy(&mut equ_reader, &mut writer));
                    }
                },

                _ => ()

            }
        }

        Ok(())
    }
}

impl<R> Response<R> where R: Read + Send + 'static {
    /// Turns this response into a `Response<Box<Read + Send>>`.
    pub fn boxed(self) -> ResponseBox {
        Response {
            reader: Box::new(self.reader) as Box<Read + Send>,
            status_code: self.status_code,
            headers: self.headers,
            data_length: self.data_length,
        }
    }
}

impl Response<File> {
    /// Builds a new `Response` from a `File`.
    ///
    /// The `Content-Type` will **not** be automatically detected,
    ///  you must set it yourself.
    pub fn from_file(file: File) -> Response<File> {
        let file_size = file.metadata().ok().map(|v| v.len() as usize);

        Response::new(
            StatusCode(200),
            Vec::with_capacity(0),
            file,
            file_size,
            None,
        )
    }
}

impl Response<Cursor<Vec<u8>>> {
    pub fn from_data<D>(data: D) -> Response<Cursor<Vec<u8>>> where D: Into<Vec<u8>> {
        let data = data.into();
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            Vec::with_capacity(0),
            Cursor::new(data),
            Some(data_len),
            None,
        )
    }

    pub fn from_string<S>(data: S) -> Response<Cursor<Vec<u8>>> where S: Into<String> {
        let data = data.into();
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            vec![
                Header::from_bytes(&b"Content-Type"[..], &b"text/plain; charset=UTF-8"[..]).unwrap()
            ],
            Cursor::new(data.into_bytes()),
            Some(data_len),
            None,
        )
    }
}

impl Response<io::Empty> {
    /// Builds an empty `Response` with the given status code.
    pub fn empty<S>(status_code: S) -> Response<io::Empty> where S: Into<StatusCode> {
        Response::new(
            status_code.into(),
            Vec::with_capacity(0),
            io::empty(),
            Some(0),
            None,
        )
    }

    /// DEPRECATED. Use `empty` instead.
    pub fn new_empty(status_code: StatusCode) -> Response<io::Empty> {
        Response::empty(status_code)
    }
}

impl Clone for Response<io::Empty> {
    fn clone(&self) -> Response<io::Empty> {
        Response {
            reader: io::empty(),
            status_code: self.status_code.clone(),
            headers: self.headers.clone(),
            data_length: self.data_length.clone(),
        }
    }
}
<commit_msg>Prevent unwrap by using if..let<commit_after>// Copyright 2015 The tiny-http Contributors
//
// 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 common::{Header, HTTPVersion, StatusCode};

use std::ascii::AsciiExt;
use std::cmp::Ordering;
use std::sync::mpsc::Receiver;

use std::io::{self, Read, Write, Cursor};
use std::io::Result as IoResult;

use std::fs::File;

use std::str::FromStr;

/// Object representing an HTTP response whose purpose is to be given to a `Request`.
///
/// Some headers cannot be changed. Trying to define the value
/// of one of these will have no effect:
///
///  - `Accept-Ranges`
///  - `Connection`
///  - `Content-Range`
///  - `Trailer`
///  - `Transfer-Encoding`
///  - `Upgrade`
///
/// Some headers have special behaviors:
///
///  - `Content-Encoding`: If you define this header, the library
///     will assume that the data from the `Read` object has the specified encoding
///     and will just pass-through.
///
///  - `Content-Length`: The length of the data should be set manually
///     using the `Reponse` object's API. Attempting to set the value of this
///     header will be equivalent to modifying the size of the data but the header
///     itself may not be present in the final result.
///
pub struct Response<R> where R: Read {
    reader: R,
    status_code: StatusCode,
    headers: Vec<Header>,
    data_length: Option<usize>,
}

/// A `Response` without a template parameter.
pub type ResponseBox = Response<Box<Read + Send>>;

/// Transfer encoding to use when sending the message.
/// Note that only *supported* encoding are listed here.
enum TransferEncoding {
    Identity,
    Chunked,
}

impl FromStr for TransferEncoding {
    type Err = ();

    fn from_str(input: &str) -> Result<TransferEncoding, ()> {
        if input.eq_ignore_ascii_case("identity") {
            Ok(TransferEncoding::Identity)
        } else if input.eq_ignore_ascii_case("chunked") {
            Ok(TransferEncoding::Chunked)
        } else {
            Err(())
        }
    }
}

/// Builds a Date: header with the current date.
fn build_date_header() -> Header {
    // FIXME: right date
    Header::from_bytes(&b"Date"[..], &b"Wed, 15 Nov 1995 06:25:24 GMT"[..]).unwrap()
}

fn write_message_header<W>(mut writer: W, http_version: &HTTPVersion,
                           status_code: &StatusCode, headers: &[Header])
                           -> IoResult<()> where W: Write
{
    // writing status line
    try!(write!(&mut writer, "HTTP/{}.{} {} {}\r\n",
        http_version.0,
        http_version.1,
        status_code.0,
        status_code.get_default_reason_phrase()
    ));

    // writing headers
    for header in headers.iter() {
        try!(writer.write_all(header.field.as_str().as_ref()));
        try!(write!(&mut writer, ": "));
        try!(writer.write_all(header.value.as_ref().as_ref()));
        try!(write!(&mut writer, "\r\n"));
    }

    // separator between header and data
    try!(write!(&mut writer, "\r\n"));

    Ok(())
}

fn choose_transfer_encoding(request_headers: &[Header], http_version: &HTTPVersion,
                            entity_length: &Option<usize>, has_additional_headers: bool)
    -> TransferEncoding
{
    use util;

    // HTTP 1.0 doesn't support other encoding
    if *http_version <= (1, 0) {
        return TransferEncoding::Identity;
    }

    // parsing the request's TE header
    let user_request = request_headers.iter()
        // finding TE
        .find(|h| h.field.equiv(&"TE"))

        // getting its value
        .map(|h| h.value.clone())

        // getting the corresponding TransferEncoding
        .and_then(|value| {
            // getting list of requested elements
            let mut parse = util::parse_header_value(value.as_str());     // TODO: remove conversion

            // sorting elements by most priority
            parse.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));

            // trying to parse each requested encoding
            for value in parse.iter() {
                // q=0 are ignored
                if value.1 <= 0.0 { continue }

                match <TransferEncoding as FromStr>::from_str(value.0) {
                    Ok(te) => return Some(te),
                    _ => ()     // unrecognized/unsupported encoding
                };
            }

            // encoding not found
            None
        });

    //
    if let Some(user_request) = user_request {
        return user_request;
    }

    // if we have additional headers, using chunked
    if has_additional_headers {
        return TransferEncoding::Chunked;
    }

    // if we don't have a Content-Length, or if the Content-Length is too big, using chunks writer
    let chunks_threshold = 32768;
    if entity_length.as_ref().map_or(true, |val| *val >= chunks_threshold) {
        return TransferEncoding::Chunked;
    }

    // Identity by default
    TransferEncoding::Identity
}

impl<R> Response<R> where R: Read {
    /// Creates a new Response object.
    ///
    /// The `additional_headers` argument is a receiver that
    ///  may provide headers even after the response has been sent.
    ///
    /// All the other arguments are straight-forward.
    pub fn new(status_code: StatusCode, headers: Vec<Header>,
               data: R, data_length: Option<usize>,
               additional_headers: Option<Receiver<Header>>)
                -> Response<R>
    {
        let mut response = Response {
            reader: data,
            status_code: status_code,
            headers: Vec::with_capacity(16),
            data_length: data_length,
        };

        for h in headers {
            response.add_header(h)
        }

        // dummy implementation
        if let Some(additional_headers) = additional_headers {
            for h in additional_headers.iter() {
                response.add_header(h)
            }
        }

        response
    }

    /// Adds a header to the list.
    /// Does all the checks.
    pub fn add_header<H>(&mut self, header: H) where H: Into<Header> {
        let header = header.into();

        // ignoring forbidden headers
        if header.field.equiv(&"Accept-Ranges") ||
           header.field.equiv(&"Connection") ||
           header.field.equiv(&"Content-Range") ||
           header.field.equiv(&"Trailer") ||
           header.field.equiv(&"Transfer-Encoding") ||
           header.field.equiv(&"Upgrade")
        {
            return;
        }

        // if the header is Content-Length, setting the data length
        if header.field.equiv(&"Content-Length") {
            match <usize as FromStr>::from_str(header.value.as_str()) {
                Ok(val) => self.data_length = Some(val),
                Err(_) => ()      // wrong value for content-length
            };

            return;
        }

        self.headers.push(header);
    }

    /// Returns the same request, but with an additional header.
    ///
    /// Some headers cannot be modified and some other have a
    ///  special behavior. See the documentation above.
    #[inline]
    pub fn with_header<H>(mut self, header: H) -> Response<R> where H: Into<Header> {
        self.add_header(header.into());
        self
    }

    /// Returns the same request, but with a different status code.
    #[inline]
    pub fn with_status_code<S>(mut self, code: S) -> Response<R> where S: Into<StatusCode> {
        self.status_code = code.into();
        self
    }

    /// Returns the same request, but with different data.
    pub fn with_data<S>(self, reader: S, data_length: Option<usize>) -> Response<S> where S: Read {
        Response {
            reader: reader,
            headers: self.headers,
            status_code: self.status_code,
            data_length: data_length,
        }
    }

    /// Prints the HTTP response to a writer.
    ///
    /// This function is the one used to send the response to the client's socket.
    /// Therefore you shouldn't expect anything pretty-printed or even readable.
    ///
    /// The HTTP version and headers passed as arguments are used to
    ///  decide which features (most notably, encoding) to use.
    ///
    /// Note: does not flush the writer.
    pub fn raw_print<W: Write>(mut self, mut writer: W, http_version: HTTPVersion,
                               request_headers: &[Header], do_not_send_body: bool,
                               upgrade: Option<&str>)
                               -> IoResult<()>
    {
        let mut transfer_encoding = Some(choose_transfer_encoding(request_headers,
                                    &http_version, &self.data_length, false /* TODO */));

        // add `Date` if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Date")).is_none() {
            self.headers.insert(0, build_date_header());
        }

        // add `Server` if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Server")).is_none() {
            self.headers.insert(0,
                Header::from_bytes(&b"Server"[..], &b"tiny-http (Rust)"[..]).unwrap()
            );
        }

        // handling upgrade
        if let Some(upgrade) = upgrade {
            self.headers.insert(0, Header::from_bytes(&b"Upgrade"[..], upgrade.as_bytes()).unwrap());
            self.headers.insert(0, Header::from_bytes(&b"Connection"[..], &b"upgrade"[..]).unwrap());
            transfer_encoding = None;
        }

        // checking whether to ignore the body of the response
        let do_not_send_body = do_not_send_body ||
            match self.status_code.0 {
                // sattus code 1xx, 204 and 304 MUST not include a body
                100...199 | 204 | 304 => true,
                _ => false
            };

        // preparing headers for transfer
        match transfer_encoding {
            Some(TransferEncoding::Chunked) => {
                self.headers.push(
                    Header::from_bytes(&b"Transfer-Encoding"[..], &b"chunked"[..]).unwrap()
                )
            },

            Some(TransferEncoding::Identity) => {
                assert!(self.data_length.is_some());
                let data_length = self.data_length.unwrap();

                self.headers.push(
                    Header::from_bytes(&b"Content-Length"[..], format!("{}", data_length).as_bytes()).unwrap()
                )
            },

            _ => ()
        };

        // sending headers
        try!(write_message_header(writer.by_ref(), &http_version,
            &self.status_code, &self.headers));

        // sending the body
        if !do_not_send_body {
            match transfer_encoding {

                Some(TransferEncoding::Chunked) => {
                    use chunked_transfer::Encoder;

                    let mut writer = Encoder::new(writer);
                    try!(io::copy(&mut self.reader, &mut writer));
                },

                Some(TransferEncoding::Identity) => {
                    use util::EqualReader;

                    assert!(self.data_length.is_some());
                    let data_length = self.data_length.unwrap();

                    if data_length >= 1 {
                        let (mut equ_reader, _) =
                            EqualReader::new(self.reader.by_ref(), data_length);
                        try!(io::copy(&mut equ_reader, &mut writer));
                    }
                },

                _ => ()

            }
        }

        Ok(())
    }
}

impl<R> Response<R> where R: Read + Send + 'static {
    /// Turns this response into a `Response<Box<Read + Send>>`.
    pub fn boxed(self) -> ResponseBox {
        Response {
            reader: Box::new(self.reader) as Box<Read + Send>,
            status_code: self.status_code,
            headers: self.headers,
            data_length: self.data_length,
        }
    }
}

impl Response<File> {
    /// Builds a new `Response` from a `File`.
    ///
    /// The `Content-Type` will **not** be automatically detected,
    ///  you must set it yourself.
    pub fn from_file(file: File) -> Response<File> {
        let file_size = file.metadata().ok().map(|v| v.len() as usize);

        Response::new(
            StatusCode(200),
            Vec::with_capacity(0),
            file,
            file_size,
            None,
        )
    }
}

impl Response<Cursor<Vec<u8>>> {
    pub fn from_data<D>(data: D) -> Response<Cursor<Vec<u8>>> where D: Into<Vec<u8>> {
        let data = data.into();
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            Vec::with_capacity(0),
            Cursor::new(data),
            Some(data_len),
            None,
        )
    }

    pub fn from_string<S>(data: S) -> Response<Cursor<Vec<u8>>> where S: Into<String> {
        let data = data.into();
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            vec![
                Header::from_bytes(&b"Content-Type"[..], &b"text/plain; charset=UTF-8"[..]).unwrap()
            ],
            Cursor::new(data.into_bytes()),
            Some(data_len),
            None,
        )
    }
}

impl Response<io::Empty> {
    /// Builds an empty `Response` with the given status code.
    pub fn empty<S>(status_code: S) -> Response<io::Empty> where S: Into<StatusCode> {
        Response::new(
            status_code.into(),
            Vec::with_capacity(0),
            io::empty(),
            Some(0),
            None,
        )
    }

    /// DEPRECATED. Use `empty` instead.
    pub fn new_empty(status_code: StatusCode) -> Response<io::Empty> {
        Response::empty(status_code)
    }
}

impl Clone for Response<io::Empty> {
    fn clone(&self) -> Response<io::Empty> {
        Response {
            reader: io::empty(),
            status_code: self.status_code.clone(),
            headers: self.headers.clone(),
            data_length: self.data_length.clone(),
        }
    }
}
<|endoftext|>


<commit_before>use chrono::prelude::*;
use serde::de::{self, Deserializer, MapAccess, Visitor};
use serde::Deserialize;
use std::fmt;
use std::str::FromStr;
use std::time::SystemTime;

#[derive(Debug, PartialEq)]
pub struct PeriodTime(SystemTime);

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename = "usage_report")]
pub struct UsageReport {
    pub metric: String,
    pub period: Period,
    pub period_start: PeriodTime,
    pub period_end: PeriodTime,
    pub max_value: u64,
    pub current_value: u64,
}

// Unfortunately the XML output from Apisonator includes a rather useless "usage_reports" tag that
// is then followed by a "usage_report" tag in each UsageReport, so we need to wrap that up.
#[derive(Debug, Deserialize, PartialEq)]
pub enum UsageReports {
    #[serde(rename = "usage_report")]
    UsageReports(Vec<UsageReport>),
}

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename = "status")]
pub struct Authorization {
    authorized: bool,
    plan: String,
    usage_reports: UsageReports,
}

#[derive(Debug, Deserialize, PartialEq)]
pub struct PeriodInstance {
    start: SystemTime,
    end: SystemTime,
}

#[derive(Debug, PartialEq)]
pub enum Period {
    Minute,
    Hour,
    Day,
    Week,
    Month,
    Year,
    Eternity,
}

struct PeriodStringVisitor;

impl<'de> Visitor<'de> for PeriodStringVisitor {
    type Value = Period;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("a string that represents a period")
    }

    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    where
        E: de::Error,
    {
        match v {
            "minute" => Ok(Period::Minute),
            "hour" => Ok(Period::Hour),
            "day" => Ok(Period::Day),
            "week" => Ok(Period::Week),
            "month" => Ok(Period::Month),
            "year" => Ok(Period::Year),
            "eternity" => Ok(Period::Eternity),
            _ => Err(E::custom("Invalid period")),
        }
    }
}

impl<'de> Deserialize<'de> for Period {
    fn deserialize<D>(deserializer: D) -> Result<Period, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_any(PeriodStringVisitor)
    }
}

struct TimestampVisitor;

impl<'de> Visitor<'de> for TimestampVisitor {
    type Value = PeriodTime;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("a string that represents a timestamp")
    }

    fn visit_map<V>(self, mut map: V) -> Result<PeriodTime, V::Error>
    where
        V: MapAccess<'de>,
    {
        // We know there's only one key with one value - Note: probably safe to skip
        let _key: Option<String> = map.next_key()?;
        let timestamp: String = map.next_value()?;

        let dt = DateTime::parse_from_str(timestamp.as_str(), "%Y-%m-%d %H:%M:%S %z").unwrap();

        Ok(PeriodTime(dt.into()))
    }
}

impl<'de> Deserialize<'de> for PeriodTime {
    fn deserialize<D>(deserializer: D) -> Result<PeriodTime, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_any(TimestampVisitor)
    }
}

#[derive(Debug, Deserialize, PartialEq)]
pub struct UsageData {
    max_value: u64,
    current_value: u64,
}

#[derive(Debug, Deserialize, PartialEq)]
pub struct Metric(pub String);

impl FromStr for Authorization {
    type Err = serde_xml_rs::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        serde_xml_rs::from_str(s)
    }
}

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

    #[test]
    fn parse() {
        let s = r##"
        <?xml version="1.0" encoding="UTF-8"?>
        <status>
            <authorized>true</authorized>
            <plan>App Plan</plan>
            <usage_reports>
                <usage_report metric="products" period="minute">
                    <period_start>2019-06-05 16:24:00 +0000</period_start>
                    <period_end>2019-06-05 16:25:00 +0000</period_end>
                    <max_value>5</max_value>
                    <current_value>0</current_value>
                </usage_report>
                <usage_report metric="products" period="month">
                    <period_start>2019-06-01 00:00:00 +0000</period_start>
                    <period_end>2019-07-01 00:00:00 +0000</period_end>
                    <max_value>50</max_value>
                    <current_value>0</current_value>
                </usage_report>
            </usage_reports>
        </status>
        "##;

        let parsed_auth = Authorization::from_str(s).unwrap();

        let expected_auth = Authorization {
            authorized: true,
            plan: String::from("App Plan"),
            usage_reports: UsageReports::UsageReports(vec![
                UsageReport {
                    metric: String::from("products"),
                    period: Period::Minute,
                    period_start: PeriodTime(Utc.ymd(2019, 6, 5).and_hms(16, 24, 0).into()),
                    period_end: PeriodTime(Utc.ymd(2019, 6, 5).and_hms(16, 25, 0).into()),
                    max_value: 5,
                    current_value: 0,
                },
                UsageReport {
                    metric: String::from("products"),
                    period: Period::Month,
                    period_start: PeriodTime(Utc.ymd(2019, 6, 1).and_hms(0, 0, 0).into()),
                    period_end: PeriodTime(Utc.ymd(2019, 7, 1).and_hms(0, 0, 0).into()),
                    max_value: 50,
                    current_value: 0,
                },
            ]),
        };

        assert_eq!(parsed_auth, expected_auth);
    }
}
<commit_msg>response: add conversions PeriodTime <=> SystemTime<commit_after>use chrono::prelude::*;
use serde::de::{self, Deserializer, MapAccess, Visitor};
use serde::Deserialize;
use std::fmt;
use std::str::FromStr;
use std::time::SystemTime;

#[derive(Debug, PartialEq)]
pub struct PeriodTime(SystemTime);

impl From<SystemTime> for PeriodTime {
    fn from(st: SystemTime) -> Self {
        PeriodTime(st)
    }
}

impl From<PeriodTime> for SystemTime {
    fn from(pt: PeriodTime) -> Self {
        pt.0
    }
}

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename = "usage_report")]
pub struct UsageReport {
    pub metric: String,
    pub period: Period,
    pub period_start: PeriodTime,
    pub period_end: PeriodTime,
    pub max_value: u64,
    pub current_value: u64,
}

// Unfortunately the XML output from Apisonator includes a rather useless "usage_reports" tag that
// is then followed by a "usage_report" tag in each UsageReport, so we need to wrap that up.
#[derive(Debug, Deserialize, PartialEq)]
pub enum UsageReports {
    #[serde(rename = "usage_report")]
    UsageReports(Vec<UsageReport>),
}

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename = "status")]
pub struct Authorization {
    authorized: bool,
    plan: String,
    usage_reports: UsageReports,
}

#[derive(Debug, Deserialize, PartialEq)]
pub struct PeriodInstance {
    start: SystemTime,
    end: SystemTime,
}

#[derive(Debug, PartialEq)]
pub enum Period {
    Minute,
    Hour,
    Day,
    Week,
    Month,
    Year,
    Eternity,
}

struct PeriodStringVisitor;

impl<'de> Visitor<'de> for PeriodStringVisitor {
    type Value = Period;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("a string that represents a period")
    }

    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    where
        E: de::Error,
    {
        match v {
            "minute" => Ok(Period::Minute),
            "hour" => Ok(Period::Hour),
            "day" => Ok(Period::Day),
            "week" => Ok(Period::Week),
            "month" => Ok(Period::Month),
            "year" => Ok(Period::Year),
            "eternity" => Ok(Period::Eternity),
            _ => Err(E::custom("Invalid period")),
        }
    }
}

impl<'de> Deserialize<'de> for Period {
    fn deserialize<D>(deserializer: D) -> Result<Period, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_any(PeriodStringVisitor)
    }
}

struct TimestampVisitor;

impl<'de> Visitor<'de> for TimestampVisitor {
    type Value = PeriodTime;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("a string that represents a timestamp")
    }

    fn visit_map<V>(self, mut map: V) -> Result<PeriodTime, V::Error>
    where
        V: MapAccess<'de>,
    {
        // We know there's only one key with one value - Note: probably safe to skip
        let _key: Option<String> = map.next_key()?;
        let timestamp: String = map.next_value()?;

        let dt = DateTime::parse_from_str(timestamp.as_str(), "%Y-%m-%d %H:%M:%S %z").unwrap();

        Ok(PeriodTime(dt.into()))
    }
}

impl<'de> Deserialize<'de> for PeriodTime {
    fn deserialize<D>(deserializer: D) -> Result<PeriodTime, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_any(TimestampVisitor)
    }
}

#[derive(Debug, Deserialize, PartialEq)]
pub struct UsageData {
    max_value: u64,
    current_value: u64,
}

#[derive(Debug, Deserialize, PartialEq)]
pub struct Metric(pub String);

impl FromStr for Authorization {
    type Err = serde_xml_rs::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        serde_xml_rs::from_str(s)
    }
}

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

    #[test]
    fn parse() {
        let s = r##"
        <?xml version="1.0" encoding="UTF-8"?>
        <status>
            <authorized>true</authorized>
            <plan>App Plan</plan>
            <usage_reports>
                <usage_report metric="products" period="minute">
                    <period_start>2019-06-05 16:24:00 +0000</period_start>
                    <period_end>2019-06-05 16:25:00 +0000</period_end>
                    <max_value>5</max_value>
                    <current_value>0</current_value>
                </usage_report>
                <usage_report metric="products" period="month">
                    <period_start>2019-06-01 00:00:00 +0000</period_start>
                    <period_end>2019-07-01 00:00:00 +0000</period_end>
                    <max_value>50</max_value>
                    <current_value>0</current_value>
                </usage_report>
            </usage_reports>
        </status>
        "##;

        let parsed_auth = Authorization::from_str(s).unwrap();

        let expected_auth = Authorization {
            authorized: true,
            plan: String::from("App Plan"),
            usage_reports: UsageReports::UsageReports(vec![
                UsageReport {
                    metric: String::from("products"),
                    period: Period::Minute,
                    period_start: PeriodTime(Utc.ymd(2019, 6, 5).and_hms(16, 24, 0).into()),
                    period_end: PeriodTime(Utc.ymd(2019, 6, 5).and_hms(16, 25, 0).into()),
                    max_value: 5,
                    current_value: 0,
                },
                UsageReport {
                    metric: String::from("products"),
                    period: Period::Month,
                    period_start: PeriodTime(Utc.ymd(2019, 6, 1).and_hms(0, 0, 0).into()),
                    period_end: PeriodTime(Utc.ymd(2019, 7, 1).and_hms(0, 0, 0).into()),
                    max_value: 50,
                    current_value: 0,
                },
            ]),
        };

        assert_eq!(parsed_auth, expected_auth);
    }
}
<|endoftext|>


<commit_before>//! MemTable is a in-memory table representation.
//!
//! MemTable is designed to be used to contain the result or for fastest processing.

use rustc_serialize::Decodable;

use session::Session;
use err::{Result, Void, void_ok};
use rows::*;
use types::Ty;

pub struct MemTable
{
	types      : Vec<Ty>,
	field_names: Vec<String>,

	pages      : Vec<Page>,
	row_num    : usize
}

impl MemTable
{
	pub fn new(session: &Session, types: &Vec<Ty>, fields_name: &Vec<&str>) -> MemTable
	{
		MemTable {
			types      : types.clone(),
			field_names: ::util::str::to_owned_vec(fields_name),
			pages      : Vec::new(),
			row_num    : 0
		}
	}
}

pub struct DecodedRecords<'a, D>
{
	pages: &'a Vec<Page>,
	marker: ::std::marker::PhantomData<D>,
}

impl<'a, D> Iterator for DecodedRecords<'a, D> where D: Decodable {
  type Item = Result<D>;

  fn next(&mut self) -> Option<Result<D>> {
  	unimplemented!()
  }
}

impl MemTable
{
	pub fn row_num(&self) -> usize
	{
		self.row_num
	}

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

	pub fn types(&self) -> &Vec<Ty>
	{
		&self.types
	}

	pub fn field_names(&self) -> &Vec<String>
	{
		&self.field_names
	}

	pub fn reader<'a, D: Decodable>(&'a self) -> DecodedRecords<'a, D>
	{
		DecodedRecords {
			pages: &self.pages,
			marker: ::std::marker::PhantomData
		}
	}

	pub fn write(&mut self, page: &Page) -> Void
	{
		self.row_num += page.value_count() as usize;
		self.pages.push(page.copy());

		void_ok
	}

	pub fn close(&mut self) -> Void
	{
		self.pages.clear();

		void_ok
	}
}<commit_msg>Add type schema to DecodeRecords.<commit_after>//! MemTable is a in-memory table representation.
//!
//! MemTable is designed to be used to contain the result or for fastest processing.

use rustc_serialize::Decodable;

use session::Session;
use err::{Result, Void, void_ok};
use rows::*;
use types::Ty;

pub struct MemTable
{
	types      : Vec<Ty>,
	field_names: Vec<String>,

	pages      : Vec<Page>,
	row_num    : usize
}

impl MemTable
{
	pub fn new(session: &Session, types: &Vec<Ty>, fields_name: &Vec<&str>) -> MemTable
	{
		MemTable {
			types      : types.clone(),
			field_names: ::util::str::to_owned_vec(fields_name),
			pages      : Vec::new(),
			row_num    : 0
		}
	}
}

pub struct DecodedRecords<'a, D>
{
	pages: &'a Vec<Page>,
	types: &'a Vec<Ty>,
	marker: ::std::marker::PhantomData<D>,
}

impl<'a, D> Iterator for DecodedRecords<'a, D> where D: Decodable {
  type Item = Result<D>;

  fn next(&mut self) -> Option<Result<D>> {
  	unimplemented!()
  }
}

impl MemTable
{
	pub fn row_num(&self) -> usize
	{
		self.row_num
	}

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

	pub fn types(&self) -> &Vec<Ty>
	{
		&self.types
	}

	pub fn field_names(&self) -> &Vec<String>
	{
		&self.field_names
	}

	pub fn reader<'a, D: Decodable>(&'a self) -> DecodedRecords<'a, D>
	{
		DecodedRecords {
			pages: &self.pages,
			types: &self.types,
			marker: ::std::marker::PhantomData
		}
	}

	pub fn write(&mut self, page: &Page) -> Void
	{
		self.row_num += page.value_count() as usize;
		self.pages.push(page.copy());

		void_ok
	}

	pub fn close(&mut self) -> Void
	{
		self.pages.clear();

		void_ok
	}
}<|endoftext|>


<commit_before>use std::cmp::Ordering;
use std::fmt;
use std::hash::{self, Hash};
use std::marker::PhantomData;
use std::mem::{self, ManuallyDrop};
use std::ops;
use std::ptr;

#[cfg(not(feature = "std"))]
use alloc::alloc::{self, Layout};
#[cfg(feature = "std")]
use std::alloc::{self, Layout};

#[cfg(feature = "unsize")]
use std::marker::Unsize;
#[cfg(feature = "unsize")]
use std::ops::CoerceUnsized;

#[cfg(feature = "unsize")]
impl<T: ?Sized + Unsize<U>, U: ?Sized, Space> CoerceUnsized<SmallBox<U, Space>>
    for SmallBox<T, Space>
{}

#[cfg(all(feature = "heap", not(feature = "std")))]
use alloc::boxed::Box;

/// A box container that only stores item on stack
pub struct SmallBox<T: ?Sized, Space> {
    space: ManuallyDrop<Space>,
    ptr: *const T,
    _phantom: PhantomData<T>,
}

impl<T: ?Sized, Space> SmallBox<T, Space> {
    /// Box value on stack or heap depending on its size
    ///
    /// # Example
    ///
    /// ```
    /// use smallbox::SmallBox;
    /// use smallbox::space::*;
    ///
    /// let small: SmallBox<_, S4> = SmallBox::new([0usize; 2]);
    /// let large: SmallBox<_, S4> = SmallBox::new([1usize; 8]);
    ///
    /// assert_eq!(small.len(), 2);
    /// assert_eq!(large[7], 1);
    ///
    /// assert!(large.heaped() == true);
    /// ```
    pub fn new(val: T) -> SmallBox<T, Space>
    where
        T: Sized,
    {
        unsafe {
            let mut space = ManuallyDrop::new(mem::uninitialized::<Space>());

            let (ptr, ptr_copy): (*const T, *mut T) = if mem::size_of::<T>()
                > mem::size_of::<Space>()
                || mem::align_of::<T>() > mem::align_of::<Space>()
            {
                // Heap
                let layout = Layout::new::<T>();
                let heap_ptr = alloc::alloc(layout) as *mut T;
                (heap_ptr, heap_ptr)
            } else {
                // Stack
                (ptr::null(), mem::transmute(&mut space))
            };

            ptr::copy_nonoverlapping(&val, ptr_copy, 1);

            mem::forget(val);

            SmallBox {
                space,
                ptr,
                _phantom: PhantomData,
            }
        }
    }

    /// Change the capacity of `SmallBox`
    ///
    /// This method may move stack-allocated data to heap
    /// if the inline space is not sufficient. Once the data
    /// is stored on heap, it'll never be moved again.
    ///
    /// # Example
    ///
    /// ```
    /// use smallbox::SmallBox;
    /// use smallbox::space::{S2, S4};
    ///
    /// let s: SmallBox::<_, S4> = SmallBox::new([0usize; 4]);
    /// let m: SmallBox::<_, S2> = s.resize();
    /// ```
    pub fn resize<ToSpace>(self) -> SmallBox<T, ToSpace> {
        unsafe {
            let mut space = ManuallyDrop::new(mem::uninitialized::<ToSpace>());

            let ptr = if self.ptr.is_null() {
                // original data is on stack
                let (ptr, ptr_copy): (*const T, *mut u8) = if mem::size_of_val::<T>(&*self)
                    > mem::size_of::<ToSpace>()
                    || mem::align_of_val::<T>(&*self) > mem::align_of::<ToSpace>()
                {
                    // but we have to move it to heap
                    let mut ptr = self.ptr;

                    let layout = Layout::for_value::<T>(&*self);
                    let heap_ptr = alloc::alloc(layout) as *mut u8;

                    let ptr_ptr = &mut ptr as *mut _ as *mut usize;
                    ptr_ptr.write(heap_ptr as usize);

                    (ptr, heap_ptr)
                } else {
                    // still store it on stack
                    (self.ptr, mem::transmute(&mut space))
                };

                ptr::copy_nonoverlapping(
                    &self.space as *const _ as *const u8,
                    ptr_copy,
                    mem::size_of_val::<T>(&*self),
                );

                ptr
            } else {
                // don't touch anything if the data is already on heap
                self.ptr
            };

            mem::forget(self);

            SmallBox {
                space,
                ptr,
                _phantom: PhantomData,
            }
        }
    }

    /// Returns true if the data is heap-allocated
    pub fn heaped(&self) -> bool {
        !self.ptr.is_null()
    }

    unsafe fn as_ptr(&self) -> *const T {
        let mut ptr = self.ptr;

        if ptr.is_null() {
            let ptr_ptr = &mut ptr as *mut _ as *mut usize;
            ptr_ptr.write(mem::transmute(&self.space));
        }

        ptr
    }
}

impl<T: ?Sized, Space> ops::Deref for SmallBox<T, Space> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.as_ptr() }
    }
}

impl<T: ?Sized, Space> ops::DerefMut for SmallBox<T, Space> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *(self.as_ptr() as *const _ as *mut _) }
    }
}

impl<T: ?Sized, Space> ops::Drop for SmallBox<T, Space> {
    fn drop(&mut self) {
        unsafe {
            let layout = Layout::for_value::<T>(&*self);
            ptr::drop_in_place(&mut **self);
            if !self.ptr.is_null() {
                alloc::dealloc(self.ptr as *mut u8, layout);
            }
        }
    }
}

impl<T: ?Sized + fmt::Display, Space> fmt::Display for SmallBox<T, Space> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&**self, f)
    }
}

impl<T: ?Sized + fmt::Debug, Space> fmt::Debug for SmallBox<T, Space> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&**self, f)
    }
}

impl<T: ?Sized, Space> fmt::Pointer for SmallBox<T, Space> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // It's not possible to extract the inner Unique directly from the Box,
        // instead we cast it to a *const which aliases the Unique
        let ptr: *const T = &**self;
        fmt::Pointer::fmt(&ptr, f)
    }
}

impl<T: ?Sized + PartialEq, Space> PartialEq for SmallBox<T, Space> {
    #[inline]
    fn eq(&self, other: &SmallBox<T, Space>) -> bool {
        PartialEq::eq(&**self, &**other)
    }
    #[inline]
    fn ne(&self, other: &SmallBox<T, Space>) -> bool {
        PartialEq::ne(&**self, &**other)
    }
}

impl<T: ?Sized + PartialOrd, Space> PartialOrd for SmallBox<T, Space> {
    #[inline]
    fn partial_cmp(&self, other: &SmallBox<T, Space>) -> Option<Ordering> {
        PartialOrd::partial_cmp(&**self, &**other)
    }
    #[inline]
    fn lt(&self, other: &SmallBox<T, Space>) -> bool {
        PartialOrd::lt(&**self, &**other)
    }
    #[inline]
    fn le(&self, other: &SmallBox<T, Space>) -> bool {
        PartialOrd::le(&**self, &**other)
    }
    #[inline]
    fn ge(&self, other: &SmallBox<T, Space>) -> bool {
        PartialOrd::ge(&**self, &**other)
    }
    #[inline]
    fn gt(&self, other: &SmallBox<T, Space>) -> bool {
        PartialOrd::gt(&**self, &**other)
    }
}

impl<T: ?Sized + Ord, Space> Ord for SmallBox<T, Space> {
    #[inline]
    fn cmp(&self, other: &SmallBox<T, Space>) -> Ordering {
        Ord::cmp(&**self, &**other)
    }
}

impl<T: ?Sized + Eq, Space> Eq for SmallBox<T, Space> {}

impl<T: ?Sized + Hash, Space> Hash for SmallBox<T, Space> {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        (**self).hash(state);
    }
}

#[cfg(test)]
mod tests {
    use super::SmallBox;
    use space::*;
    #[cfg(feature = "unsize")]
    use std::any::Any;

    #[test]
    fn basic() {
        let stacked: SmallBox<usize, S1> = SmallBox::new(1234usize);
        assert!(*stacked == 1234);

        let heaped: SmallBox<(usize, usize), S1> = SmallBox::new((0, 1));
        assert!(*heaped == (0, 1));
    }

    #[test]
    #[cfg(feature = "unsize")]
    fn test_downcast() {
        let stacked: SmallBox<Any, S1> = SmallBox::new(1234usize);
        if let Some(num) = stacked.downcast_ref::<usize>() {
            assert_eq!(*num, 1234);
        } else {
            unreachable!();
        }

        let heaped: SmallBox<Any, S1> = SmallBox::new([0usize, 1]);
        if let Some(array) = heaped.downcast_ref::<[usize; 2]>() {
            assert_eq!(*array, [0, 1]);
        } else {
            unreachable!();
        }
    }

    #[test]
    fn test_drop() {
        use std::cell::Cell;

        #[derive(Debug)]
        struct Struct<'a>(&'a Cell<bool>);
        impl<'a> Drop for Struct<'a> {
            fn drop(&mut self) {
                self.0.set(true);
            }
        }

        let flag = Cell::new(false);

        let val: SmallBox<_, S2> = SmallBox::new(Struct(&flag));

        assert!(flag.get() == false);
        drop(val);
        assert!(flag.get() == true);
    }

    #[test]
    fn test_dont_drop_space() {
        struct NoDrop(S1);
        impl Drop for NoDrop {
            fn drop(&mut self) {
                unreachable!();
            }
        }

        drop(SmallBox::<_, NoDrop>::new([true]));
    }

    #[test]
    fn test_oversize() {
        let fit = SmallBox::<_, S1>::new([0usize; 1]);
        let oversize = SmallBox::<_, S1>::new([0usize; 2]);
        assert!(!fit.heaped());
        assert!(oversize.heaped());
    }

    #[test]
    fn test_resize() {
        let m = SmallBox::<_, S4>::new([0usize; 2]);
        let l = m.resize::<S8>();
        assert!(!l.heaped());
        let m = l.resize::<S4>();
        assert!(!m.heaped());
        let s = m.resize::<S2>();
        assert!(!s.heaped());
        let xs = s.resize::<S1>();
        assert!(xs.heaped());
        let m = xs.resize::<S4>();
        assert!(m.heaped());
    }

    #[test]
    fn test_zst() {
        let zst = SmallBox::<_, S1>::new([0usize; 0]);
        assert_eq!(*zst, [0usize; 0]);
    }
}
<commit_msg>impl `Sync` and `Send`<commit_after>use std::cmp::Ordering;
use std::fmt;
use std::hash::{self, Hash};
use std::marker::PhantomData;
use std::mem::{self, ManuallyDrop};
use std::ops;
use std::ptr;

#[cfg(not(feature = "std"))]
use alloc::alloc::{self, Layout};
#[cfg(feature = "std")]
use std::alloc::{self, Layout};

#[cfg(feature = "unsize")]
use std::marker::Unsize;
#[cfg(feature = "unsize")]
use std::ops::CoerceUnsized;

#[cfg(feature = "unsize")]
impl<T: ?Sized + Unsize<U>, U: ?Sized, Space> CoerceUnsized<SmallBox<U, Space>>
    for SmallBox<T, Space>
{}

#[cfg(all(feature = "heap", not(feature = "std")))]
use alloc::boxed::Box;

/// A box container that only stores item on stack
pub struct SmallBox<T: ?Sized, Space> {
    space: ManuallyDrop<Space>,
    ptr: *const T,
    _phantom: PhantomData<T>,
}

impl<T: ?Sized, Space> SmallBox<T, Space> {
    /// Box value on stack or heap depending on its size
    ///
    /// # Example
    ///
    /// ```
    /// use smallbox::SmallBox;
    /// use smallbox::space::*;
    ///
    /// let small: SmallBox<_, S4> = SmallBox::new([0usize; 2]);
    /// let large: SmallBox<_, S4> = SmallBox::new([1usize; 8]);
    ///
    /// assert_eq!(small.len(), 2);
    /// assert_eq!(large[7], 1);
    ///
    /// assert!(large.heaped() == true);
    /// ```
    pub fn new(val: T) -> SmallBox<T, Space>
    where
        T: Sized,
    {
        unsafe {
            let mut space = ManuallyDrop::new(mem::uninitialized::<Space>());

            let (ptr, ptr_copy): (*const T, *mut T) = if mem::size_of::<T>()
                > mem::size_of::<Space>()
                || mem::align_of::<T>() > mem::align_of::<Space>()
            {
                // Heap
                let layout = Layout::new::<T>();
                let heap_ptr = alloc::alloc(layout) as *mut T;
                (heap_ptr, heap_ptr)
            } else {
                // Stack
                (ptr::null(), mem::transmute(&mut space))
            };

            ptr::copy_nonoverlapping(&val, ptr_copy, 1);

            mem::forget(val);

            SmallBox {
                space,
                ptr,
                _phantom: PhantomData,
            }
        }
    }

    /// Change the capacity of `SmallBox`
    ///
    /// This method may move stack-allocated data to heap
    /// if the inline space is not sufficient. Once the data
    /// is stored on heap, it'll never be moved again.
    ///
    /// # Example
    ///
    /// ```
    /// use smallbox::SmallBox;
    /// use smallbox::space::{S2, S4};
    ///
    /// let s: SmallBox::<_, S4> = SmallBox::new([0usize; 4]);
    /// let m: SmallBox::<_, S2> = s.resize();
    /// ```
    pub fn resize<ToSpace>(self) -> SmallBox<T, ToSpace> {
        unsafe {
            let mut space = ManuallyDrop::new(mem::uninitialized::<ToSpace>());

            let ptr = if self.ptr.is_null() {
                // original data is on stack
                let (ptr, ptr_copy): (*const T, *mut u8) = if mem::size_of_val::<T>(&*self)
                    > mem::size_of::<ToSpace>()
                    || mem::align_of_val::<T>(&*self) > mem::align_of::<ToSpace>()
                {
                    // but we have to move it to heap
                    let mut ptr = self.ptr;

                    let layout = Layout::for_value::<T>(&*self);
                    let heap_ptr = alloc::alloc(layout) as *mut u8;

                    let ptr_ptr = &mut ptr as *mut _ as *mut usize;
                    ptr_ptr.write(heap_ptr as usize);

                    (ptr, heap_ptr)
                } else {
                    // still store it on stack
                    (self.ptr, mem::transmute(&mut space))
                };

                ptr::copy_nonoverlapping(
                    &self.space as *const _ as *const u8,
                    ptr_copy,
                    mem::size_of_val::<T>(&*self),
                );

                ptr
            } else {
                // don't touch anything if the data is already on heap
                self.ptr
            };

            mem::forget(self);

            SmallBox {
                space,
                ptr,
                _phantom: PhantomData,
            }
        }
    }

    /// Returns true if the data is heap-allocated
    pub fn heaped(&self) -> bool {
        !self.ptr.is_null()
    }

    unsafe fn as_ptr(&self) -> *const T {
        let mut ptr = self.ptr;

        if ptr.is_null() {
            let ptr_ptr = &mut ptr as *mut _ as *mut usize;
            ptr_ptr.write(mem::transmute(&self.space));
        }

        ptr
    }
}

impl<T: ?Sized, Space> ops::Deref for SmallBox<T, Space> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.as_ptr() }
    }
}

impl<T: ?Sized, Space> ops::DerefMut for SmallBox<T, Space> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *(self.as_ptr() as *const _ as *mut _) }
    }
}

impl<T: ?Sized, Space> ops::Drop for SmallBox<T, Space> {
    fn drop(&mut self) {
        unsafe {
            let layout = Layout::for_value::<T>(&*self);
            ptr::drop_in_place(&mut **self);
            if !self.ptr.is_null() {
                alloc::dealloc(self.ptr as *mut u8, layout);
            }
        }
    }
}

impl<T: ?Sized + fmt::Display, Space> fmt::Display for SmallBox<T, Space> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&**self, f)
    }
}

impl<T: ?Sized + fmt::Debug, Space> fmt::Debug for SmallBox<T, Space> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&**self, f)
    }
}

impl<T: ?Sized, Space> fmt::Pointer for SmallBox<T, Space> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // It's not possible to extract the inner Unique directly from the Box,
        // instead we cast it to a *const which aliases the Unique
        let ptr: *const T = &**self;
        fmt::Pointer::fmt(&ptr, f)
    }
}

impl<T: ?Sized + PartialEq, Space> PartialEq for SmallBox<T, Space> {
    #[inline]
    fn eq(&self, other: &SmallBox<T, Space>) -> bool {
        PartialEq::eq(&**self, &**other)
    }
    #[inline]
    fn ne(&self, other: &SmallBox<T, Space>) -> bool {
        PartialEq::ne(&**self, &**other)
    }
}

impl<T: ?Sized + PartialOrd, Space> PartialOrd for SmallBox<T, Space> {
    #[inline]
    fn partial_cmp(&self, other: &SmallBox<T, Space>) -> Option<Ordering> {
        PartialOrd::partial_cmp(&**self, &**other)
    }
    #[inline]
    fn lt(&self, other: &SmallBox<T, Space>) -> bool {
        PartialOrd::lt(&**self, &**other)
    }
    #[inline]
    fn le(&self, other: &SmallBox<T, Space>) -> bool {
        PartialOrd::le(&**self, &**other)
    }
    #[inline]
    fn ge(&self, other: &SmallBox<T, Space>) -> bool {
        PartialOrd::ge(&**self, &**other)
    }
    #[inline]
    fn gt(&self, other: &SmallBox<T, Space>) -> bool {
        PartialOrd::gt(&**self, &**other)
    }
}

impl<T: ?Sized + Ord, Space> Ord for SmallBox<T, Space> {
    #[inline]
    fn cmp(&self, other: &SmallBox<T, Space>) -> Ordering {
        Ord::cmp(&**self, &**other)
    }
}

impl<T: ?Sized + Eq, Space> Eq for SmallBox<T, Space> {}

impl<T: ?Sized + Hash, Space> Hash for SmallBox<T, Space> {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        (**self).hash(state);
    }
}

unsafe impl<T: ?Sized + Send, Space> Send for SmallBox<T, Space> {}
unsafe impl<T: ?Sized + Sync, Space> Sync for SmallBox<T, Space> {}

#[cfg(test)]
mod tests {
    use super::SmallBox;
    use space::*;
    #[cfg(feature = "unsize")]
    use std::any::Any;

    #[test]
    fn basic() {
        let stacked: SmallBox<usize, S1> = SmallBox::new(1234usize);
        assert!(*stacked == 1234);

        let heaped: SmallBox<(usize, usize), S1> = SmallBox::new((0, 1));
        assert!(*heaped == (0, 1));
    }

    #[test]
    #[cfg(feature = "unsize")]
    fn test_downcast() {
        let stacked: SmallBox<Any, S1> = SmallBox::new(1234usize);
        if let Some(num) = stacked.downcast_ref::<usize>() {
            assert_eq!(*num, 1234);
        } else {
            unreachable!();
        }

        let heaped: SmallBox<Any, S1> = SmallBox::new([0usize, 1]);
        if let Some(array) = heaped.downcast_ref::<[usize; 2]>() {
            assert_eq!(*array, [0, 1]);
        } else {
            unreachable!();
        }
    }

    #[test]
    fn test_drop() {
        use std::cell::Cell;

        #[derive(Debug)]
        struct Struct<'a>(&'a Cell<bool>);
        impl<'a> Drop for Struct<'a> {
            fn drop(&mut self) {
                self.0.set(true);
            }
        }

        let flag = Cell::new(false);

        let val: SmallBox<_, S2> = SmallBox::new(Struct(&flag));

        assert!(flag.get() == false);
        drop(val);
        assert!(flag.get() == true);
    }

    #[test]
    fn test_dont_drop_space() {
        struct NoDrop(S1);
        impl Drop for NoDrop {
            fn drop(&mut self) {
                unreachable!();
            }
        }

        drop(SmallBox::<_, NoDrop>::new([true]));
    }

    #[test]
    fn test_oversize() {
        let fit = SmallBox::<_, S1>::new([0usize; 1]);
        let oversize = SmallBox::<_, S1>::new([0usize; 2]);
        assert!(!fit.heaped());
        assert!(oversize.heaped());
    }

    #[test]
    fn test_resize() {
        let m = SmallBox::<_, S4>::new([0usize; 2]);
        let l = m.resize::<S8>();
        assert!(!l.heaped());
        let m = l.resize::<S4>();
        assert!(!m.heaped());
        let s = m.resize::<S2>();
        assert!(!s.heaped());
        let xs = s.resize::<S1>();
        assert!(xs.heaped());
        let m = xs.resize::<S4>();
        assert!(m.heaped());
    }

    #[test]
    fn test_zst() {
        let zst = SmallBox::<_, S1>::new([0usize; 0]);
        assert_eq!(*zst, [0usize; 0]);
    }
}
<|endoftext|>


<commit_before>use std::fmt;

pub struct Subtitle {
    seq: i64,
    start: i64,
    end: i64,
    text: String,
}

impl Subtitle {
    pub fn new(seq: i64, start: i64, end: i64, text: &str) -> Subtitle {
        Subtitle {
            seq: seq,
            start: start,
            end: end,
            text: text.to_string(),
        }
    }
    pub fn get_start(&self) -> i64 {
        self.start
    }
    pub fn get_end(&self) -> i64 {
        self.end
    }
    pub fn get_text(&self) -> &str {
        &self.text
    }
}

impl fmt::Display for Subtitle {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Subtitle #{} ({} -> {}): {}",
        self.seq, self.start, self.end, self.text)
    }
}
<commit_msg>Update subtitle.rs<commit_after>/* Part of srtcli */
use std::fmt;

pub struct Subtitle {
    seq: i64,
    start: i64,
    end: i64,
    text: String,
}

impl Subtitle {
    pub fn new(seq: i64, start: i64, end: i64, text: &str) -> Subtitle {
        Subtitle {
            seq: seq,
            start: start,
            end: end,
            text: text.to_string(),
        }
    }
    pub fn get_start(&self) -> i64 {
        self.start
    }
    pub fn get_end(&self) -> i64 {
        self.end
    }
    pub fn get_text(&self) -> &str {
        &self.text
    }
}

impl fmt::Display for Subtitle {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Subtitle #{} ({} -> {}): {}",
        self.seq, self.start, self.end, self.text)
    }
}
<|endoftext|>


<commit_before>//! Works only with correct paths or no arguments at all

use std::env;
use std::fs;
use std::path::Path;

fn main() -> Result<(), std::io::Error> {
    // ignoring all arguments except the 1st
    if let Some(path) = env::args().nth(1) {
        // check if the program received an argument
        print_files(Path::new(&path))?;
    } else {
        // note that current_dir value might be invalid, so it's a Result
        print_files(&env::current_dir()?)?;
    };
    Ok(())
}

fn print_files(path: &Path) -> std::io::Result<()> {
    let mut entries: Vec<_> = fs::read_dir(path)?
        .map(|x| x.unwrap().file_name())
        .collect();
    entries.sort();
    for x in entries {
        println!("{}", x.to_string_lossy());
    }
    Ok(())
}
<commit_msg>condense import. functional style<commit_after>//! Works only with correct paths or no arguments at all

use std::path::Path;
use std::{env, fs};

fn main() -> Result<(), std::io::Error> {
    // ignoring all arguments except the 1st
    if let Some(path) = env::args().nth(1) {
        // check if the program received an argument
        print_files(Path::new(&path))?;
    } else {
        // note that current_dir value might be invalid, so it's a Result
        print_files(&env::current_dir()?)?;
    };
    Ok(())
}

fn print_files(path: &Path) -> std::io::Result<()> {
    let mut entries: Vec<_> = fs::read_dir(path)?
        .flat_map(|res| res)
        .map(|f| f.file_name())
        .collect();
    // read_dir does not guarantee order
    entries.sort();
    entries.iter().for_each(|f| {
        println!("{}", f.to_string_lossy());
    });
    Ok(())
}
<|endoftext|>


<commit_before>pub use libc::dev_t;
pub use libc::stat as FileStat;

use {Errno, Result, NixPath};
use fcntl::AtFlags;
use libc::{self, mode_t};
use std::mem;
use std::os::unix::io::RawFd;

mod ffi {
    use libc::{c_char, c_int, mode_t, dev_t};
    pub use libc::{stat, fstat, lstat};

    extern {
        pub fn mknod(pathname: *const c_char, mode: mode_t, dev: dev_t) -> c_int;
        pub fn umask(mask: mode_t) -> mode_t;
    }
}

libc_bitflags!(
    pub flags SFlag: mode_t {
        S_IFIFO,
        S_IFCHR,
        S_IFDIR,
        S_IFBLK,
        S_IFREG,
        S_IFLNK,
        S_IFSOCK,
        S_IFMT,
    }
);

bitflags! {
    pub struct Mode: mode_t {
        const S_IRWXU = libc::S_IRWXU;
        const S_IRUSR = libc::S_IRUSR;
        const S_IWUSR = libc::S_IWUSR;
        const S_IXUSR = libc::S_IXUSR;

        const S_IRWXG = libc::S_IRWXG;
        const S_IRGRP = libc::S_IRGRP;
        const S_IWGRP = libc::S_IWGRP;
        const S_IXGRP = libc::S_IXGRP;

        const S_IRWXO = libc::S_IRWXO;
        const S_IROTH = libc::S_IROTH;
        const S_IWOTH = libc::S_IWOTH;
        const S_IXOTH = libc::S_IXOTH;

        const S_ISUID = libc::S_ISUID as mode_t;
        const S_ISGID = libc::S_ISGID as mode_t;
        const S_ISVTX = libc::S_ISVTX as mode_t;
    }
}

pub fn mknod<P: ?Sized + NixPath>(path: &P, kind: SFlag, perm: Mode, dev: dev_t) -> Result<()> {
    let res = try!(path.with_nix_path(|cstr| {
        unsafe {
            ffi::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev)
        }
    }));

    Errno::result(res).map(drop)
}

#[cfg(target_os = "linux")]
pub fn major(dev: dev_t) -> u64 {
    ((dev >> 32) & 0xfffff000) |
    ((dev >>  8) & 0x00000fff)
}

#[cfg(target_os = "linux")]
pub fn minor(dev: dev_t) -> u64 {
    ((dev >> 12) & 0xffffff00) |
    ((dev      ) & 0x000000ff)
}

#[cfg(target_os = "linux")]
pub fn makedev(major: u64, minor: u64) -> dev_t {
    ((major & 0xfffff000) << 32) |
    ((major & 0x00000fff) <<  8) |
    ((minor & 0xffffff00) << 12) |
    ((minor & 0x000000ff)      )
}

pub fn umask(mode: Mode) -> Mode {
    let prev = unsafe { ffi::umask(mode.bits() as mode_t) };
    Mode::from_bits(prev).expect("[BUG] umask returned invalid Mode")
}

pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
    let mut dst = unsafe { mem::uninitialized() };
    let res = try!(path.with_nix_path(|cstr| {
        unsafe {
            ffi::stat(cstr.as_ptr(), &mut dst as *mut FileStat)
        }
    }));

    try!(Errno::result(res));

    Ok(dst)
}

pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
    let mut dst = unsafe { mem::uninitialized() };
    let res = try!(path.with_nix_path(|cstr| {
        unsafe {
            ffi::lstat(cstr.as_ptr(), &mut dst as *mut FileStat)
        }
    }));

    try!(Errno::result(res));

    Ok(dst)
}

pub fn fstat(fd: RawFd) -> Result<FileStat> {
    let mut dst = unsafe { mem::uninitialized() };
    let res = unsafe { ffi::fstat(fd, &mut dst as *mut FileStat) };

    try!(Errno::result(res));

    Ok(dst)
}

pub fn fstatat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, f: AtFlags) -> Result<FileStat> {
    let mut dst = unsafe { mem::uninitialized() };
    let res = try!(pathname.with_nix_path(|cstr| {
        unsafe { libc::fstatat(dirfd, cstr.as_ptr(), &mut dst as *mut FileStat, f.bits() as libc::c_int) }
    }));

    try!(Errno::result(res));

    Ok(dst)
}

<commit_msg>reuse mknod/umask/fstat/lstat from libc<commit_after>pub use libc::dev_t;
pub use libc::stat as FileStat;

use {Errno, Result, NixPath};
use fcntl::AtFlags;
use libc::{self, mode_t};
use std::mem;
use std::os::unix::io::RawFd;

libc_bitflags!(
    pub flags SFlag: mode_t {
        S_IFIFO,
        S_IFCHR,
        S_IFDIR,
        S_IFBLK,
        S_IFREG,
        S_IFLNK,
        S_IFSOCK,
        S_IFMT,
    }
);

bitflags! {
    pub struct Mode: mode_t {
        const S_IRWXU = libc::S_IRWXU;
        const S_IRUSR = libc::S_IRUSR;
        const S_IWUSR = libc::S_IWUSR;
        const S_IXUSR = libc::S_IXUSR;

        const S_IRWXG = libc::S_IRWXG;
        const S_IRGRP = libc::S_IRGRP;
        const S_IWGRP = libc::S_IWGRP;
        const S_IXGRP = libc::S_IXGRP;

        const S_IRWXO = libc::S_IRWXO;
        const S_IROTH = libc::S_IROTH;
        const S_IWOTH = libc::S_IWOTH;
        const S_IXOTH = libc::S_IXOTH;

        const S_ISUID = libc::S_ISUID as mode_t;
        const S_ISGID = libc::S_ISGID as mode_t;
        const S_ISVTX = libc::S_ISVTX as mode_t;
    }
}

pub fn mknod<P: ?Sized + NixPath>(path: &P, kind: SFlag, perm: Mode, dev: dev_t) -> Result<()> {
    let res = try!(path.with_nix_path(|cstr| {
        unsafe {
            libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev)
        }
    }));

    Errno::result(res).map(drop)
}

#[cfg(target_os = "linux")]
pub fn major(dev: dev_t) -> u64 {
    ((dev >> 32) & 0xfffff000) |
    ((dev >>  8) & 0x00000fff)
}

#[cfg(target_os = "linux")]
pub fn minor(dev: dev_t) -> u64 {
    ((dev >> 12) & 0xffffff00) |
    ((dev      ) & 0x000000ff)
}

#[cfg(target_os = "linux")]
pub fn makedev(major: u64, minor: u64) -> dev_t {
    ((major & 0xfffff000) << 32) |
    ((major & 0x00000fff) <<  8) |
    ((minor & 0xffffff00) << 12) |
    ((minor & 0x000000ff)      )
}

pub fn umask(mode: Mode) -> Mode {
    let prev = unsafe { libc::umask(mode.bits() as mode_t) };
    Mode::from_bits(prev).expect("[BUG] umask returned invalid Mode")
}

pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
    let mut dst = unsafe { mem::uninitialized() };
    let res = try!(path.with_nix_path(|cstr| {
        unsafe {
            libc::stat(cstr.as_ptr(), &mut dst as *mut FileStat)
        }
    }));

    try!(Errno::result(res));

    Ok(dst)
}

pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
    let mut dst = unsafe { mem::uninitialized() };
    let res = try!(path.with_nix_path(|cstr| {
        unsafe {
            libc::lstat(cstr.as_ptr(), &mut dst as *mut FileStat)
        }
    }));

    try!(Errno::result(res));

    Ok(dst)
}

pub fn fstat(fd: RawFd) -> Result<FileStat> {
    let mut dst = unsafe { mem::uninitialized() };
    let res = unsafe { libc::fstat(fd, &mut dst as *mut FileStat) };

    try!(Errno::result(res));

    Ok(dst)
}

pub fn fstatat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, f: AtFlags) -> Result<FileStat> {
    let mut dst = unsafe { mem::uninitialized() };
    let res = try!(pathname.with_nix_path(|cstr| {
        unsafe { libc::fstatat(dirfd, cstr.as_ptr(), &mut dst as *mut FileStat, f.bits() as libc::c_int) }
    }));

    try!(Errno::result(res));

    Ok(dst)
}

<|endoftext|>