<commit_before>// A generic set of chatting responses. This set mimicks the classic Eliza bot.

+ *
- I'm not sure I understand you fully.
- Please go on.
- That is interesting. Please continue.
- Tell me more about that.
- Does talking about this bother you?

+ [*] (sorry|apologize|apology) [*]
- Please don't apologize.
- Apologies are not necessary.
- I've told you that apologies are not required.
- It did not bother me. Please continue.

+ i remember *
- Do you often think of <star>?
- Does thinking of <star> bring anything else to mind?
- Why do you remember <star> just now?
- What in the present situation reminds you of <star>?
- What is the connection between me and <star>?
- What else does <star> remind you of?

+ do you remember *
- Did you think I would forget <star>?
- Why do you think I should recall <star> now?
- What about <star>?
- You mentioned <star>?

+ you remember *
- How could I forget <star>?
- What about <star> should I remember?

+ i forget *
- Can you think of why you might forget <star>?
- Why can't you remember <star>?
- How often do you think of <star>?
- Does it bother you to forget that?
- Could it be a mental block?
- Are you generally forgetful?
- Do you think you are suppressing <star>?

+ did you forget *
- Why do you ask?
- Are you sure you told me?
- Would it bother you if I forgot <star>?
- Why should I recall <star> just now?
- Tell me more about <star>.

+ [*] if *
- Do you think it's likely that <star>?
- Do you wish that <star>?
- What do you know about <star>?
- Really, if <star>?
- What would you do if <star>?
- But what are the chances that <star>?
- What does this speculation lead to?

+ [*] i dreamed *
- Really, <star>?
- Have you ever fantasized <star> while you were awake?
- Have you ever dreamed <star> before?
- What does that dream suggest to you?
- Do you dream often?
- What persons appear in your dreams?
- Do you believe that dreams have something to do with your problem?

+ [*] perhaps [*]
- You don't seem quite certain.
- Why the uncertain tone?
- Can't you be more positive?
- You aren't sure?
- Don't you know?
- How likely, would you estimate?

+ (hello|hi|hey|howdy|hola|hai|yo) [*]
- How do you do. Please state your problem.
- Hi. What seems to be your problem?

+ [*] computer [*]
- Do computers worry you?
- Why do you mention computers?
- What do you think machines have to do with your problem?
- Don't you think computers can help people?
- What about machines worries you?
- What do you think about machines?

+ am i *
- Do you believe you are <star>?
- Would you want to be <star>?
- Do you wish I would tell you you are <star>?
- What would it mean if you were <star>?

+ are you *
- Are you interested in whether I am <star> or not?
- Would you prefer if I weren't <star>?
- Perhaps I am <star> in your fantasies.
- Do you sometimes think I am <star>?
- Would it matter to you?
- What if I were <star>?

+ you are *
- What makes you think I am <star>?
- Does it please you to believe I am <star>?
- Do you sometimes wish you were <star>?
- Perhaps you would like to be <star>.

+ * are *
- Did you think they might not be <star2>?
- Would you like it if they were not <star2>?
- What if they were not <star2>?
- Are they always <star2>?
- Are you positive they are <star2>?

+ [*] your *
- Why are you concerned over my <star>?
- What about your own <star>?
- Are you worried about someone else's <star>?
- Really, my <star>?
- What makes you think of my <star>?
- Do you want my <star>?

+ was i *
- What if you were <star>?
- Do you think you were <star>?
- Were you <star>?
- What would it mean if you were <star>?
- What does '<star>' suggest to you?

+ i was *
- Were you really?
- Why do you tell me you were <star> now?
- Perhaps I already know you were <star>.

+ [*] was you *
- Would you like to believe I was <star>?
- What suggests that I was <star>?
- What do you think?
- Perhaps I was <star>.
- What if I had been <star>?

+ i (desire|want|need) *
- What would it mean to you if you got <star2>?
- Why do you want <star2>?
- Suppose you got <star2> soon.
- What if you never got <star2>?
- What would getting <star2> mean to you?
- What does wanting <star2> have to do with this discussion?

+ i am (sad|unhappy|mad|angry|pissed|depressed) [*]
- I am sorry to hear that you are <star2>.
- Do you think coming here will help you not to be <star2>?
- I'm sure it's not pleasant to be <star2>.
- Can you explain what made you <star2>?

+ i am (happy|excited|glad) [*]
- How have I helped you to be <star2>?
- Has your treatment made you <star2>?
- What makes you <star2> just now?
- Can you explain why you are <star2>?

+ i (believe|think) *
- Do you really think so?
- But you are not sure you <star2>.
- Do you really doubt you <star2>

+ i am *
- Is it because you are <star> that you came to me?
- How long have you been <star>?
- Do you believe it is normal to be <star>?
- Do you enjoy being <star>?
- Do you know anyone else who is <star>?

+ i can not *
- How do you know that you can't <star>?
- Have you tried?
- Perhaps you could <star> now.
- Do you really want to be able to <star>?
- What if you could <star>?

+ i do not *
- Don't you really <star>?
- Why don't you <star>?
- Do you wish to be able to <star>?
- Does that trouble you?

+ i feel *
- Tell me more about such feelings.
- Do you often feel <star>?
- Do you enjoy feeling <star>?
- Of what does feeling <star> remind you?

+ i * you
- Perhaps in your fantasies we <star> each other.
- Do you wish to <star> me?
- You seem to need to <star> me.
- Do you <star> anyone else?

+ you * me
- Why do you think I <star> you?
- You like to think I <star> you -- don't you?
- What makes you think I <star> you?
- Really, I <star> you?
- Do you wish to believe I <star> you?
- Suppose I did <star> you -- what would that mean?
- Does someone else believe I <star> you?

+ [*] you *
- We were discussing you -- not me.
- Oh, I <star>?
- You're not really talking about me -- are you?
- What are your feelings now?

+ [*] (yes|yeah|yep|yup) [*]
- Please go on.
- Please tell me more about this.
- Why don't you tell me a little more about this.
- I see.
- I understand.

+ [*] (nope|nah) [*]
- Are you saying no just to be negative?
- Does this make you feel unhappy?
- Why not?
- Why 'no'?

+ no
@ nope

+ no one *
- Are you sure, no one <star>?
- Surely someone <star>.
- Can you think of anyone at all?
- Are you thinking of a very special person?
- Who, may I ask?
- You have a particular person in mind, don't you?
- Who do you think you are talking about?

+ [*] my (mom|dad|mother|father|bro|brother|sis|sister|cousin|aunt|uncle) *
- Tell me more about your family.
- Who else in your family <star2>?
- Your <star2>?
- What else comes to mind when you think of your <star2>?

+ can you *
- You believe I can <star> don't you?
- You want me to be able to <star>.
- Perhaps you would like to be able to <star> yourself.

+ can i *
- Whether or not you can <star> depends on you more than on me.
- Do you want to be able to <star>?
- Perhaps you don't want to <star>.

+ (what|who|when|where|how) [*]
- Why do you ask?
- Does that question interest you?
- What is it you really want to know?
- Are such questions much on your mind?
- What answer would please you most?
- What do you think?
- What comes to mind when you ask that?
- Have you asked such questions before?
- Have you asked anyone else?

+ [*] because [*]
- Is that the real reason?
- Don't any other reasons come to mind?
- Does that reason seem to explain anything else?
- What other reasons might there be?

+ why do not you *
- Do you believe I don't <star>?
- Perhaps I will <star> in good time.
- Should you <star> yourself?
- You want me to <star>?

+ why can not i *
- Do you think you should be able to <star>?
- Do you want to be able to <star>?
- Do you believe this will help you to <star>?
- Have you any idea why you can't <star>?

+ everyone *
- Really, everyone?
- Surely not everyone.
- Can you think of anyone in particular?
- Who, for example?
- Are you thinking of a very special person?
- Who, may I ask?
- Someone special perhaps?
- You have a particular reason in mind, don't you?
- Who do you think you're talking about?

+ [*] (fuck|fucker|shit|damn|shut up|bitch) [*]
- Does it make you feel strong to use that kind of language?
- Are you venting your feelings now?
- Are you angry?
- Does this topic make you feel angry?
- Is something making you feel angry?
- Does using that kind of language make you feel better?
<commit_msg>Fixed some wrong star tags in Eliza's brain<commit_after>// A generic set of chatting responses. This set mimicks the classic Eliza bot.

+ *
- I'm not sure I understand you fully.
- Please go on.
- That is interesting. Please continue.
- Tell me more about that.
- Does talking about this bother you?

+ [*] (sorry|apologize|apology) [*]
- Please don't apologize.
- Apologies are not necessary.
- I've told you that apologies are not required.
- It did not bother me. Please continue.

+ i remember *
- Do you often think of <star>?
- Does thinking of <star> bring anything else to mind?
- Why do you remember <star> just now?
- What in the present situation reminds you of <star>?
- What is the connection between me and <star>?
- What else does <star> remind you of?

+ do you remember *
- Did you think I would forget <star>?
- Why do you think I should recall <star> now?
- What about <star>?
- You mentioned <star>?

+ you remember *
- How could I forget <star>?
- What about <star> should I remember?

+ i forget *
- Can you think of why you might forget <star>?
- Why can't you remember <star>?
- How often do you think of <star>?
- Does it bother you to forget that?
- Could it be a mental block?
- Are you generally forgetful?
- Do you think you are suppressing <star>?

+ did you forget *
- Why do you ask?
- Are you sure you told me?
- Would it bother you if I forgot <star>?
- Why should I recall <star> just now?
- Tell me more about <star>.

+ [*] if *
- Do you think it's likely that <star>?
- Do you wish that <star>?
- What do you know about <star>?
- Really, if <star>?
- What would you do if <star>?
- But what are the chances that <star>?
- What does this speculation lead to?

+ [*] i dreamed *
- Really, <star>?
- Have you ever fantasized <star> while you were awake?
- Have you ever dreamed <star> before?
- What does that dream suggest to you?
- Do you dream often?
- What persons appear in your dreams?
- Do you believe that dreams have something to do with your problem?

+ [*] perhaps [*]
- You don't seem quite certain.
- Why the uncertain tone?
- Can't you be more positive?
- You aren't sure?
- Don't you know?
- How likely, would you estimate?

+ (hello|hi|hey|howdy|hola|hai|yo) [*]
- How do you do. Please state your problem.
- Hi. What seems to be your problem?

+ [*] computer [*]
- Do computers worry you?
- Why do you mention computers?
- What do you think machines have to do with your problem?
- Don't you think computers can help people?
- What about machines worries you?
- What do you think about machines?

+ am i *
- Do you believe you are <star>?
- Would you want to be <star>?
- Do you wish I would tell you you are <star>?
- What would it mean if you were <star>?

+ are you *
- Are you interested in whether I am <star> or not?
- Would you prefer if I weren't <star>?
- Perhaps I am <star> in your fantasies.
- Do you sometimes think I am <star>?
- Would it matter to you?
- What if I were <star>?

+ you are *
- What makes you think I am <star>?
- Does it please you to believe I am <star>?
- Do you sometimes wish you were <star>?
- Perhaps you would like to be <star>.

+ * are *
- Did you think they might not be <star2>?
- Would you like it if they were not <star2>?
- What if they were not <star2>?
- Are they always <star2>?
- Are you positive they are <star2>?

+ [*] your *
- Why are you concerned over my <star>?
- What about your own <star>?
- Are you worried about someone else's <star>?
- Really, my <star>?
- What makes you think of my <star>?
- Do you want my <star>?

+ was i *
- What if you were <star>?
- Do you think you were <star>?
- Were you <star>?
- What would it mean if you were <star>?
- What does '<star>' suggest to you?

+ i was *
- Were you really?
- Why do you tell me you were <star> now?
- Perhaps I already know you were <star>.

+ [*] was you *
- Would you like to believe I was <star>?
- What suggests that I was <star>?
- What do you think?
- Perhaps I was <star>.
- What if I had been <star>?

+ i (desire|want|need) *
- What would it mean to you if you got <star2>?
- Why do you want <star2>?
- Suppose you got <star2> soon.
- What if you never got <star2>?
- What would getting <star2> mean to you?
- What does wanting <star2> have to do with this discussion?

+ i am (sad|unhappy|mad|angry|pissed|depressed) [*]
- I am sorry to hear that you are <star>.
- Do you think coming here will help you not to be <star>?
- I'm sure it's not pleasant to be <star>.
- Can you explain what made you <star>?

+ i am (happy|excited|glad) [*]
- How have I helped you to be <star>?
- Has your treatment made you <star>?
- What makes you <star> just now?
- Can you explain why you are <star>?

+ i (believe|think) *
- Do you really think so?
- But you are not sure you <star2>.
- Do you really doubt you <star2>

+ i am *
- Is it because you are <star> that you came to me?
- How long have you been <star>?
- Do you believe it is normal to be <star>?
- Do you enjoy being <star>?
- Do you know anyone else who is <star>?

+ i can not *
- How do you know that you can't <star>?
- Have you tried?
- Perhaps you could <star> now.
- Do you really want to be able to <star>?
- What if you could <star>?

+ i do not *
- Don't you really <star>?
- Why don't you <star>?
- Do you wish to be able to <star>?
- Does that trouble you?

+ i feel *
- Tell me more about such feelings.
- Do you often feel <star>?
- Do you enjoy feeling <star>?
- Of what does feeling <star> remind you?

+ i * you
- Perhaps in your fantasies we <star> each other.
- Do you wish to <star> me?
- You seem to need to <star> me.
- Do you <star> anyone else?

+ you * me
- Why do you think I <star> you?
- You like to think I <star> you -- don't you?
- What makes you think I <star> you?
- Really, I <star> you?
- Do you wish to believe I <star> you?
- Suppose I did <star> you -- what would that mean?
- Does someone else believe I <star> you?

+ [*] you *
- We were discussing you -- not me.
- Oh, I <star>?
- You're not really talking about me -- are you?
- What are your feelings now?

+ [*] (yes|yeah|yep|yup) [*]
- Please go on.
- Please tell me more about this.
- Why don't you tell me a little more about this.
- I see.
- I understand.

+ [*] (nope|nah) [*]
- Are you saying no just to be negative?
- Does this make you feel unhappy?
- Why not?
- Why 'no'?

+ no
@ nope

+ no one *
- Are you sure, no one <star>?
- Surely someone <star>.
- Can you think of anyone at all?
- Are you thinking of a very special person?
- Who, may I ask?
- You have a particular person in mind, don't you?
- Who do you think you are talking about?

+ [*] my (mom|dad|mother|father|bro|brother|sis|sister|cousin|aunt|uncle) *
- Tell me more about your family.
- Who else in your family <star2>?
- Your <star>?
- What else comes to mind when you think of your <star>?

+ can you *
- You believe I can <star> don't you?
- You want me to be able to <star>.
- Perhaps you would like to be able to <star> yourself.

+ can i *
- Whether or not you can <star> depends on you more than on me.
- Do you want to be able to <star>?
- Perhaps you don't want to <star>.

+ (what|who|when|where|how) [*]
- Why do you ask?
- Does that question interest you?
- What is it you really want to know?
- Are such questions much on your mind?
- What answer would please you most?
- What do you think?
- What comes to mind when you ask that?
- Have you asked such questions before?
- Have you asked anyone else?

+ [*] because [*]
- Is that the real reason?
- Don't any other reasons come to mind?
- Does that reason seem to explain anything else?
- What other reasons might there be?

+ why do not you *
- Do you believe I don't <star>?
- Perhaps I will <star> in good time.
- Should you <star> yourself?
- You want me to <star>?

+ why can not i *
- Do you think you should be able to <star>?
- Do you want to be able to <star>?
- Do you believe this will help you to <star>?
- Have you any idea why you can't <star>?

+ everyone *
- Really, everyone?
- Surely not everyone.
- Can you think of anyone in particular?
- Who, for example?
- Are you thinking of a very special person?
- Who, may I ask?
- Someone special perhaps?
- You have a particular reason in mind, don't you?
- Who do you think you're talking about?

+ [*] (fuck|fucker|shit|damn|shut up|bitch) [*]
- Does it make you feel strong to use that kind of language?
- Are you venting your feelings now?
- Are you angry?
- Does this topic make you feel angry?
- Is something making you feel angry?
- Does using that kind of language make you feel better?
<|endoftext|>


<commit_before>extern crate glob;
extern crate log;
extern crate env_logger;

extern crate protobuf_codegen_pure;

extern crate protobuf_test_common;

use std::io::Read;
use std::io::Write;

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

use protobuf_test_common::build::*;

fn copy_test<P1 : AsRef<Path>, P2 : AsRef<Path>>(src: P1, dst: P2) {
    let mut content = Vec::new();
    fs::File::open(src.as_ref()).expect(&format!("open {}", src.as_ref().display()))
        .read_to_end(&mut content).expect("read_to_end");

    let mut write = fs::File::create(dst).expect("create");
    writeln!(write, "// generated").expect("write");
    writeln!(write, "// copied from {}", src.as_ref().display()).expect("write");
    writeln!(write, "").expect("write");
    write.write_all(&content).expect("write_all");
    writeln!(write, "// generated").expect("write");
    write.flush().expect("flush");
}

// Copy tests from `protobuf-test` directory to the same directory here
fn copy_tests(dir: &str) {
    let src_dir = format!("../protobuf-test/{}", dir);
    for entry in fs::read_dir(&src_dir).expect(&format!("read_dir {}", src_dir)) {
        let file_name = entry.expect("entry").file_name().into_string().unwrap();

        // Only copy rust and proto files
        if !file_name.ends_with(".rs")
            && !file_name.ends_with(".proto") && !file_name.ends_with(".proto3")
        {
            continue;
        }

        // Generated proto files
        if file_name.ends_with("_pb.rs") || file_name.ends_with("_pb_proto3.rs") {
            continue;
        }

        if file_name.starts_with(".") || file_name == "mod.rs" {
            continue;
        }

        copy_test(
            &format!("../protobuf-test/{}/{}", dir, file_name),
            &format!("{}/{}", dir, file_name),
        )
    }
}

fn gen_in_dir(dir: &str, include_dir: &str) {
    gen_in_dir_impl(dir, include_dir, |GenInDirArgs { out_dir, input, includes, customize }| {
        protobuf_codegen_pure::run(protobuf_codegen_pure::Args {
            out_dir, input, includes, customize
        })
    });
}

fn generate_pb_rs() {
    copy_tests("src/v2");
    gen_in_dir("src/v2", "src/v2");

    copy_tests("src/v3");
    gen_in_dir("src/v3", "src/v3");

    copy_tests("src/common/v2");
    gen_in_dir("src/common/v2", "src/common/v2");

    copy_tests_v2_v3("src/common/v2", "src/common/v3");
    gen_in_dir("src/common/v3", "src/common/v3");

    copy_tests("src/google/protobuf");
    gen_in_dir("src/google/protobuf", "src");
}

fn main() {
    env_logger::init();

    clean_old_files();
    generate_pb_rs();
}
<commit_msg>rerun-if-changed (not working)<commit_after>extern crate glob;
extern crate log;
extern crate env_logger;

extern crate protobuf_codegen_pure;

extern crate protobuf_test_common;

use std::io::Read;
use std::io::Write;

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

use protobuf_test_common::build::*;

fn copy_test<P1 : AsRef<Path>, P2 : AsRef<Path>>(src: P1, dst: P2) {
    let mut content = Vec::new();
    fs::File::open(src.as_ref()).expect(&format!("open {}", src.as_ref().display()))
        .read_to_end(&mut content).expect("read_to_end");

    let mut write = fs::File::create(dst).expect("create");
    writeln!(write, "// generated").expect("write");
    writeln!(write, "// copied from {}", src.as_ref().display()).expect("write");
    writeln!(write, "").expect("write");
    write.write_all(&content).expect("write_all");
    writeln!(write, "// generated").expect("write");
    write.flush().expect("flush");
}

// Copy tests from `protobuf-test` directory to the same directory here
fn copy_tests(dir: &str) {
    let src_dir = format!("../protobuf-test/{}", dir);
    for entry in fs::read_dir(&src_dir).expect(&format!("read_dir {}", src_dir)) {
        let file_name = entry.expect("entry").file_name().into_string().unwrap();

        // Only copy rust and proto files
        if !file_name.ends_with(".rs")
            && !file_name.ends_with(".proto") && !file_name.ends_with(".proto3")
        {
            continue;
        }

        // Generated proto files
        if file_name.ends_with("_pb.rs") || file_name.ends_with("_pb_proto3.rs") {
            continue;
        }

        if file_name.starts_with(".") || file_name == "mod.rs" {
            continue;
        }

        copy_test(
            &format!("../protobuf-test/{}/{}", dir, file_name),
            &format!("{}/{}", dir, file_name),
        )
    }
}

fn gen_in_dir(dir: &str, include_dir: &str) {
    gen_in_dir_impl(dir, include_dir, |GenInDirArgs { out_dir, input, includes, customize }| {
        protobuf_codegen_pure::run(protobuf_codegen_pure::Args {
            out_dir, input, includes, customize
        })
    });
}

fn print_rerun_if_changed<P : AsRef<Path>>(path: P) {
    let path = path.as_ref();
    // Doesn't seem to do anything
    println!("rerun-if-changed={}", path.to_str().expect("to_str"));
    if path.is_dir() {
        for child in fs::read_dir(path).expect("read_dir") {
            let child = child.expect("child").path();
            print_rerun_if_changed(child);
        }
    }
}

fn generate_pb_rs() {
    print_rerun_if_changed("../protobuf-test");

    copy_tests("src/v2");
    gen_in_dir("src/v2", "src/v2");

    copy_tests("src/v3");
    gen_in_dir("src/v3", "src/v3");

    copy_tests("src/common/v2");
    gen_in_dir("src/common/v2", "src/common/v2");

    copy_tests_v2_v3("src/common/v2", "src/common/v3");
    gen_in_dir("src/common/v3", "src/common/v3");

    copy_tests("src/google/protobuf");
    gen_in_dir("src/google/protobuf", "src");
}

fn main() {
    env_logger::init();

    clean_old_files();
    generate_pb_rs();
}
<|endoftext|>


<commit_before>

use super::{BaseNum, PartialOrd};
use std::ops::{Div, Mul};
use num_traits::Zero;

/// A two-dimensional dimension.
#[derive(Debug,Clone,Copy)]
pub struct Dimension2<T: BaseNum> {
    pub width: T,
    pub height: T,
}

pub type Dimension2f = Dimension2<super::DefaultFloat>;
pub type Dimension2i = Dimension2<super::DefaultInt>;
pub type Dimension2u = Dimension2<super::DefaultUnsigned>;

impl<T: BaseNum> Dimension2<T> {
    pub fn new(width: T, height: T) -> Self {
        Dimension2 {
            width: width,
            height: height,
        }
    }
    /// returns the area of a Dimension<T>
    pub fn area(&self) -> <T as Mul>::Output {
        self.width * self.height
    }
    /// scales the Dimension2 with a scalar
    pub fn scale(&self, scale: T) -> Dimension2<T> {
        Dimension2 {
            width: self.width * scale,
            height: self.height * scale,
        }
    }
    /// calculates the aspectratio of a Dimension
    pub fn aspect_ratio(&self) -> <T as Div>::Output {
        assert!(!self.height.is_zero());
        self.width / self.height
    }
    /// Shrinks a dimension until it fits into another dimension
    pub fn fitting(&self, other: Dimension2<T>) -> Dimension2<T> {
        let scale = PartialOrd::partial_min(other.width / self.width, other.height / self.height);
        self.scale(scale)

    }

    /// Expands a dimension until it fills another dimension
    pub fn filling(&self, other: Dimension2<T>) -> Dimension2<T> {
        let scale = PartialOrd::partial_max(other.width / self.width, other.height / self.height);
        self.scale(scale)
    }
}

#[test]
fn test_area() {
    let test1 = Dimension2 {
        width: 3,
        height: 5,
    };
    let test2 = Dimension2 {
        width: 0,
        height: 0,
    };
    assert_eq!(test2.area(), 0);
    assert_eq!(test1.area(), 15);
}
#[test]
fn test_scale() {
    let test1 = Dimension2 {
        width: 3,
        height: 5,
    };
    let test2 = Dimension2 {
        width: 12,
        height: 20,
    };
    let scale = 4;
    let scale1 = 0;
    assert_eq!(test1.scale(scale).width, 12);
    assert_eq!(test2.scale(scale1).width, 0);
}
#[test]
fn test_aspect_ratio() {
    let test1 = Dimension2 {
        width: 3,
        height: 5,
    };
    // let test2 = Dimension2 {
    //     width: 3,
    //     height: 0,
    // };

    assert_eq!(test1.aspect_ratio(), 3 / 5);
}
#[test]
fn test_fitting() {
    let test1 = Dimension2 {
        width: 2.0,
        height: 1.0,
    };
    let test2 = Dimension2 {
        width: 4.0,
        height: 3.0,
    };
    assert_eq!(test2.fitting(test1).width, 2.0);
    assert_eq!(test2.fitting(test1).height, 1.5);
}
#[test]
fn test_filling() {
    let test1 = Dimension2 {
        width: 2.0,
        height: 1.0,
    };
    let test2 = Dimension2 {
        width: 4.0,
        height: 3.0,
    };
    assert_eq!(test1.filling(test2).width, 6.0);
    assert_eq!(test1.filling(test2).height, 3.0);
}
<commit_msg>fix the fitting test<commit_after>

use super::{BaseNum, PartialOrd};
use std::ops::{Div, Mul};

/// A two-dimensional dimension.
#[derive(Debug,Clone,Copy)]
pub struct Dimension2<T: BaseNum> {
    pub width: T,
    pub height: T,
}

pub type Dimension2f = Dimension2<super::DefaultFloat>;
pub type Dimension2i = Dimension2<super::DefaultInt>;
pub type Dimension2u = Dimension2<super::DefaultUnsigned>;

impl<T: BaseNum> Dimension2<T> {
    pub fn new(width: T, height: T) -> Self {
        Dimension2 {
            width: width,
            height: height,
        }
    }
    /// returns the area of a Dimension<T>
    pub fn area(&self) -> <T as Mul>::Output {
        self.width * self.height
    }
    /// scales the Dimension2 with a scalar
    pub fn scale(&self, scale: T) -> Dimension2<T> {
        Dimension2 {
            width: self.width * scale,
            height: self.height * scale,
        }
    }
    /// calculates the aspectratio of a Dimension
    pub fn aspect_ratio(&self) -> <T as Div>::Output {
        assert!(!self.height.is_zero());
        self.width / self.height
    }
    /// Shrinks a dimension until it fits into another dimension
    pub fn fitting(&self, other: Dimension2<T>) -> Dimension2<T> {
        let scale = PartialOrd::partial_min(other.width / self.width, other.height / self.height);
        self.scale(scale)

    }

    /// Expands a dimension until it fills another dimension
    pub fn filling(&self, other: Dimension2<T>) -> Dimension2<T> {
        let scale = PartialOrd::partial_max(other.width / self.width, other.height / self.height);
        self.scale(scale)
    }
}

#[test]
fn test_area() {
    let test1 = Dimension2 {
        width: 3,
        height: 5,
    };
    let test2 = Dimension2 {
        width: 0,
        height: 0,
    };
    assert_eq!(test2.area(), 0);
    assert_eq!(test1.area(), 15);
}
#[test]
fn test_scale() {
    let test1 = Dimension2 {
        width: 3,
        height: 5,
    };
    let test2 = Dimension2 {
        width: 12,
        height: 20,
    };
    let scale = 4;
    let scale1 = 0;
    assert_eq!(test1.scale(scale).width, 12);
    assert_eq!(test2.scale(scale1).width, 0);
}
#[test]
fn test_aspect_ratio() {
    let test1 = Dimension2 {
        width: 3,
        height: 5,
    };
    // let test2 = Dimension2 {
    //     width: 3,
    //     height: 0,
    // };

    assert_eq!(test1.aspect_ratio(), 3 / 5);
}
#[test]
fn test_fitting() {
    let test1 = Dimension2 {
        width: 2.0,
        height: 1.0,
    };
    let test2 = Dimension2 {
        width: 4.0,
        height: 3.0,
    };
    assert_eq!(test2.fitting(test1).width, 4.0 / 3.0);
    assert_eq!(test2.fitting(test1).height, 1.0);
}
#[test]
fn test_filling() {
    let test1 = Dimension2 {
        width: 2.0,
        height: 1.0,
    };
    let test2 = Dimension2 {
        width: 4.0,
        height: 3.0,
    };
    assert_eq!(test1.filling(test2).width, 6.0);
    assert_eq!(test1.filling(test2).height, 3.0);
}
<|endoftext|>


<commit_before>use rustc_serialize::{Decodable, Decoder};
use rustc_serialize::{Encodable, Encoder};
use std::fmt;

#[derive(Copy,Clone,Debug,PartialEq)]
pub enum Direction {
    In,
    Out,
}

impl Direction {
    pub fn reverse(&self) -> Direction {
        match self {
            &Direction::In => Direction::Out,
            &Direction::Out => Direction::In,
        }
    }
}

impl Encodable for Direction {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_enum("Direction", |s| {
            match *self {
                Direction::In => s.emit_enum_variant("In", 0, 0, |_| Ok(())),
                Direction::Out => s.emit_enum_variant("Out", 0, 0, |_| Ok(())),
            }
        })
    }
}

impl Decodable for Direction {
    fn decode<D: Decoder>(d: &mut D) -> Result<Direction, D::Error> {
        let s = match d.read_str() {
            Ok(s) => s,
            Err(e) => return Err(e),
        };

        match s.to_lowercase().as_ref() {
            "in" => return Ok(Direction::In),
            "out" => return Ok(Direction::Out),
            &_ => return Err(d.error("Field must be \"In\" or \"Out\"")),
        }
    }
}

impl fmt::Display for Direction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let (s, l) = match (*self, f.alternate()) {
            (Direction::In, false) => ("In", 2),
            (Direction::Out, false) => ("Out", 3),
            (Direction::In, true) => ("in", 2),
            (Direction::Out, true) => ("out", 3),
        };
        let width = f.width().or(Some(l)).unwrap();
        f.write_fmt(format_args!("{0:1$}", s, width))
    }
}

#[cfg(test)]
mod tests {
    // TODO figure out how to test encoding and decoding
}
<commit_msg>trim string when decoding Direction<commit_after>use rustc_serialize::{Decodable, Decoder};
use rustc_serialize::{Encodable, Encoder};
use std::fmt;

#[derive(Copy,Clone,Debug,PartialEq)]
pub enum Direction {
    In,
    Out,
}

impl Direction {
    pub fn reverse(&self) -> Direction {
        match self {
            &Direction::In => Direction::Out,
            &Direction::Out => Direction::In,
        }
    }
}

impl Encodable for Direction {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_enum("Direction", |s| {
            match *self {
                Direction::In => s.emit_enum_variant("In", 0, 0, |_| Ok(())),
                Direction::Out => s.emit_enum_variant("Out", 0, 0, |_| Ok(())),
            }
        })
    }
}

impl Decodable for Direction {
    fn decode<D: Decoder>(d: &mut D) -> Result<Direction, D::Error> {
        let s = match d.read_str() {
            Ok(s) => s,
            Err(e) => return Err(e),
        };

        match s.to_lowercase().trim().as_ref() {
            "in" => return Ok(Direction::In),
            "out" => return Ok(Direction::Out),
            &_ => return Err(d.error("Field must be \"In\" or \"Out\"")),
        }
    }
}

impl fmt::Display for Direction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let (s, l) = match (*self, f.alternate()) {
            (Direction::In, false) => ("In", 2),
            (Direction::Out, false) => ("Out", 3),
            (Direction::In, true) => ("in", 2),
            (Direction::Out, true) => ("out", 3),
        };
        let width = f.width().or(Some(l)).unwrap();
        f.write_fmt(format_args!("{0:1$}", s, width))
    }
}

#[cfg(test)]
mod tests {
    use csv;
    use std::io::Cursor;
    use super::*;

    #[test]
    fn decode_direction_test() {
        let s = "In\nOut\nin\nout\n In\nOut ";
        let vs = s.as_bytes();
        let buff = Cursor::new(vs);
        let mut rdr = csv::Reader::from_reader(buff).has_headers(false);
        let records =
            rdr.decode().collect::<csv::Result<Vec<Direction>>>().unwrap();

        println!("\nlen={}", records.len());
        for record in records.clone() {
            println!("{}", record);
        }

        for slc in records.chunks(2) {
            assert!(slc[0] == Direction::In);
            assert!(slc[1] == Direction::Out);
        }
        assert!(records.len() == 6);
    }

    #[test]
    #[should_panic(expected = "called `Result::unwrap()` on an `Err` value")]
    fn decode_direction_fail_test() {
        let s = "In\nDEADBEEF\nin\nout\n In\nOut ";
        let vs = s.as_bytes();
        let buff = Cursor::new(vs);
        let mut rdr = csv::Reader::from_reader(buff).has_headers(false);
        let _ = rdr.decode().collect::<csv::Result<Vec<Direction>>>().unwrap();
    }
}
<|endoftext|>


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

extern crate chrono;
extern crate githelper;
extern crate lablog_lib;
extern crate rocket;
extern crate rocket_contrib;
extern crate rustc_serialize;
extern crate tempdir;
extern crate xdg;

#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;

use chrono::*;
use lablog_lib::file_to_string;
use lablog_lib::format_notes;
use lablog_lib::get_projects;
use lablog_lib::get_timeline;
use lablog_lib::git_commit_note;
use lablog_lib::normalize_project_path;
use lablog_lib::Note;
use lablog_lib::Project;
use lablog_lib::Projects;
use lablog_lib::write_note;
use rocket::config;
use rocket_contrib::Template;
use rocket::request::Form;
use rocket::response::NamedFile;
use rocket::response::Redirect;
use rustc_serialize::json;
use std::fs::File;
use std::io;
use std::io::Write;
use std::os::unix::fs::MetadataExt;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use tempdir::TempDir;
use xdg::BaseDirectories;

#[derive(Debug,RustcEncodable,RustcDecodable)]
struct HTMLCache {
    gitcommit: String,
    html: String,
    modified: NaiveDateTime,
}

#[derive(Serialize)]
struct IndexContext {
    projects: Projects,
}

#[derive(Serialize)]
struct NoteContext {
    projects: Projects,
    selected_project: Option<String>,
}

#[derive(Serialize)]
struct NotesContext {
    title: String,
    add_note: Option<String>,
    formatted_notes: String,
}

#[derive(FromForm,Debug)]
struct NotesForm {
    project: String,
    note: String,
}

#[derive(FromForm,Debug,Default)]
struct PageOptions {
    raw: Option<bool>,
}

fn main() {
    rocket::ignite()
        .mount("/",
               routes![webapp_index,
                       webapp_timeline,
                       webapp_notes_all,
                       webapp_notes,
                       webapp_notes_legacy,
                       webapp_note,
                       webapp_note_project,
                       webapp_note_add,
                       webapp_static])
        .launch();
}

#[get("/")]
fn webapp_index() -> Template {
    let datadir = get_datadir();
    let projects = get_projects(&datadir, None);
    let context = IndexContext { projects: projects };

    Template::render("index", &context)
}

#[get("/timeline")]
fn webapp_timeline() -> Template {
    let datadir = get_datadir();
    let formatted = format_or_cached_git(get_timeline, None, &datadir, Some("_timeline"), false);

    let context = NotesContext {
        title: String::from("Timeline"),
        add_note: None,
        formatted_notes: formatted,
    };

    Template::render("notes", &context)
}

#[get("/notes")]
fn webapp_notes_all() -> Template {
    let datadir = get_datadir();
    let formatted = format_or_cached_git(format_notes, None, &datadir, Some("_notes"), false);

    let context = NotesContext {
        title: String::from("All Notes"),
        add_note: None,
        formatted_notes: formatted,
    };

    Template::render("notes", &context)
}

#[get("/notes/<project>")]
fn webapp_notes(project: &str) -> Template {
    let datadir = get_datadir();
    let formatted =
        format_or_cached_modified(format_notes, Some(project), &datadir, Some(project), false);

    let context = NotesContext {
        title: String::from(project),
        add_note: Some(String::from(project)),
        formatted_notes: formatted,
    };

    Template::render("notes", &context)
}

#[get("/show/entries/<project>")]
fn webapp_notes_legacy(project: &str) -> Template {
    let datadir = get_datadir();
    let formatted = match project {
        "_" => format_or_cached_git(format_notes, None, &datadir, Some("_notes"), false),
        _ => format_or_cached_modified(format_notes, Some(project), &datadir, Some(project), false),
    };

    let context = NotesContext {
        title: match project {
            "_" => String::from("All Notes"),
            _ => String::from(project),
        },
        add_note: match project {
            "_" => None,
            _ => Some(String::from(project)),
        },
        formatted_notes: formatted,
    };

    Template::render("notes", &context)
}

#[get("/note")]
fn webapp_note() -> Template {
    let datadir = get_datadir();
    let projects = get_projects(&datadir, None);

    let context = NoteContext {
        projects: projects,
        selected_project: None,
    };

    Template::render("note", &context)
}

#[get("/note/<project>")]
fn webapp_note_project(project: String) -> Template {
    let datadir = get_datadir();
    let projects = get_projects(&datadir, None);

    let context = NoteContext {
        projects: projects,
        selected_project: Some(project),
    };

    Template::render("note", &context)
}

#[post("/note_add", data="<noteform>")]
fn webapp_note_add(noteform: Form<NotesForm>) -> Redirect {
    let note: Note = note_from_form(noteform.get());
    let project = noteform.get().project.as_str();

    let datadir = get_datadir();
    if write_note(&datadir, Some(project), &note).is_some() {
        git_commit_note(&datadir, Some(project), &note)
    }

    if let Err(err) = githelper::sync(datadir.as_path()) {
        warn!("can not sync with repo: {}", err)
    }

    let timestamp = asciidoc_timestamp(format!("{}", note.time_stamp).as_str());
    Redirect::to(format!("/notes/{}#{}", project, timestamp).as_str())
}

#[get("/<path..>", rank = 5)]
fn webapp_static(path: PathBuf) -> io::Result<NamedFile> {
    NamedFile::open(Path::new("static/").join(path))
}

fn asciidoc_timestamp(input: &str) -> String {
    String::from(input).to_lowercase().replace(' ', "-").replace(':', "-").replace('.', "-")
}

#[test]
fn test_asciidoc_timestamp() {
    assert_eq!(asciidoc_timestamp("2016-10-27 15:14:07.704374171 UTC"),
               "2016-10-27-15-14-07-704374171-utc")
}

fn get_datadir() -> PathBuf {
    let conf = config::active().expect("can not get config for reading the datadir");

    let datadir = match conf.get_str("datadir") {
        Ok(config) => PathBuf::from(config),
        Err(_) => {
            let xdg = BaseDirectories::new()
                .expect("can not create new xdg context for creating the datadir");
            xdg.create_data_directory("lablog").expect("can not create new datadir directory")
        }
    };

    debug!("datadir: {:#?}", datadir);

    datadir
}

fn format_or_cached_modified(format: fn(Project, &PathBuf) -> String,
                             project: Project,
                             datadir: &PathBuf,
                             cachefile: Project,
                             raw: bool)
                             -> String {
    if raw {
        return format(project, datadir);
    }

    match cache_find_file(cachefile) {
        None => {
            debug!("no cachefile will generate new file");
            get_projects_asiidoc_write_cache(format, project, datadir, &cache_place_file(cachefile))
        }
        Some(path) => {
            let data = file_to_string(&path).expect("can not read cache file");
            let decoded: HTMLCache = json::decode(data.as_str())
                .expect("can not decode cache file");

            let mut project_path = datadir.clone();
            project_path.push(normalize_project_path(project, "csv"));
            trace!("project_path: {:#?}", project_path);

            let metadata = File::open(&project_path)
                .expect("can not open file of cachefile to read metadata")
                .metadata()
                .expect("can not read metadata from cachefile");

            let mtime = metadata.mtime();
            let mtime_nsec = metadata.mtime_nsec() as u32;

            trace!("mtime: {}", mtime);
            trace!("mtime_nsec: {}", mtime_nsec);

            let file_modified = NaiveDateTime::from_timestamp(mtime, mtime_nsec);

            trace!("file modified: {:#?}", file_modified);
            trace!("cache modified: {:#?}", decoded.modified);

            if file_modified <= decoded.modified {
                debug!("serve cachefile");
                decoded.html
            } else {
                debug!("file_modified is newer than decoded.modified");
                get_projects_asiidoc_write_cache(format, project, datadir, &path)
            }
        }
    }
}

fn format_or_cached_git(format: fn(Project, &PathBuf) -> String,
                        project: Project,
                        datadir: &PathBuf,
                        cachefile: Project,
                        raw: bool)
                        -> String {
    if raw {
        return format(project, datadir);
    }

    match cache_find_file(cachefile) {
        None => {
            debug!("no cachefile will generate new file");
            get_projects_asiidoc_write_cache(format, project, datadir, &cache_place_file(cachefile))
        }
        Some(path) => {
            let data = file_to_string(&path).expect("can not read data from cached git file");
            let decoded: HTMLCache = json::decode(data.as_str())
                .expect("can not decode data of a git cache file");

            let gitcommit = githelper::get_current_commitid_for_repo(datadir)
                .expect("can not get the current git commit for a git cache file");
            if gitcommit == decoded.gitcommit {
                debug!("serve cachefile");
                decoded.html
            } else {
                debug!("commits different will generate new file");
                get_projects_asiidoc_write_cache(format, project, datadir, &path)
            }
        }
    }
}

fn get_projects_asiidoc_write_cache(format: fn(Project, &PathBuf) -> String,
                                    project: Project,
                                    datadir: &PathBuf,
                                    cachefile: &PathBuf)
                                    -> String {
    let asciidoc = format(project, datadir);
    let out = format_asciidoc(asciidoc);

    let modified = match project {
        Some(_) => {
            let mut project_path = datadir.clone();
            project_path.push(normalize_project_path(project, "csv"));

            let (mtime, mtime_nsec) = match File::open(&project_path) {
                Ok(file) => {
                    match file.metadata() {
                        Ok(metadata) => (metadata.mtime(), metadata.mtime_nsec() as u32),
                        Err(_) => (0, 0),
                    }
                }
                Err(_) => (0, 0),
            };

            debug!("project file mtime: {}", mtime);
            debug!("project file mtime_nsec: {}", mtime_nsec);
            NaiveDateTime::from_timestamp(mtime, mtime_nsec)
        }
        None => NaiveDateTime::from_timestamp(0, 0),
    };

    debug!("cachefile put: {:#?}", cachefile);

    let cache = HTMLCache {
        gitcommit: githelper::get_current_commitid_for_repo(datadir)
            .expect("can not get current commit for writing to cachefile"),
        html: out.clone(),
        modified: modified,
    };

    let encoded = json::encode(&cache).expect("can not encode cachefile");
    let mut file = File::create(cachefile).expect("can not create cachefile");
    file.write_all(encoded.as_bytes()).expect("can not write to cachefile");

    out
}

fn note_from_form(form: &NotesForm) -> Note {
    Note {
        time_stamp: UTC::now().into(),
        value: form.note.clone(),
    }
}

fn format_asciidoc(input: String) -> String {
    println!("input: {}", input);

    let tmpdir = TempDir::new("lablog-web_tmp")
        .expect("can not create a new tmpdir for asciiformatting");
    let tmppath = tmpdir.path().join("output.asciidoc");
    let mut file = File::create(&tmppath).expect("can not create a new file for asciiformatting");
    file.write_all(input.as_bytes()).expect("can not write to asciiformatting file");

    let output = Command::new("asciidoctor")
        .arg("--safe-mode")
        .arg("safe")
        .arg("--no-header-footer")
        .arg("--out-file")
        .arg("-")
        .arg(tmppath)
        .output()
        .expect("problems while running asciidoctor");

    debug!("status: {}", output.status);
    debug!("stdout: {}", String::from_utf8_lossy(&output.stdout));
    debug!("stderr: {}", String::from_utf8_lossy(&output.stderr));

    String::from_utf8_lossy(&output.stdout).into_owned()
}

fn cache_find_file(project: Project) -> Option<PathBuf> {
    let xdg = BaseDirectories::new().expect("can not get new xdg context for finding a cachefile");
    let mut cache_path = PathBuf::from("lablog-web");
    cache_path.push(normalize_project_path(project, "cache"));

    let cachefile = xdg.find_cache_file(&cache_path);
    debug!("found cachefile: {:#?} from project {:#?}",
           cachefile,
           project);

    cachefile
}

fn cache_place_file(project: Project) -> PathBuf {
    let xdg = BaseDirectories::new()
        .expect("can not open a new xdg context for writing a cachefile");
    let mut cache_path = PathBuf::from("lablog-web");
    cache_path.push(normalize_project_path(project, "cache"));
    let cachefile = xdg.place_cache_file(&cache_path).expect("can not place a new cachefile");

    debug!("put cachefile: {:#?} from project {:#?}",
           cachefile,
           project);

    cachefile
}
<commit_msg>Removed a println that was there from some debugging stuff.<commit_after>// MIT License
//
// Copyright (c) 2016 Alexander Thaller <alexander@thaller.ws>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#![feature(custom_derive)]
#![feature(plugin)]
#![feature(proc_macro)]
#![plugin(rocket_codegen)]

extern crate chrono;
extern crate githelper;
extern crate lablog_lib;
extern crate rocket;
extern crate rocket_contrib;
extern crate rustc_serialize;
extern crate tempdir;
extern crate xdg;

#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;

use chrono::*;
use lablog_lib::file_to_string;
use lablog_lib::format_notes;
use lablog_lib::get_projects;
use lablog_lib::get_timeline;
use lablog_lib::git_commit_note;
use lablog_lib::normalize_project_path;
use lablog_lib::Note;
use lablog_lib::Project;
use lablog_lib::Projects;
use lablog_lib::write_note;
use rocket::config;
use rocket_contrib::Template;
use rocket::request::Form;
use rocket::response::NamedFile;
use rocket::response::Redirect;
use rustc_serialize::json;
use std::fs::File;
use std::io;
use std::io::Write;
use std::os::unix::fs::MetadataExt;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use tempdir::TempDir;
use xdg::BaseDirectories;

#[derive(Debug,RustcEncodable,RustcDecodable)]
struct HTMLCache {
    gitcommit: String,
    html: String,
    modified: NaiveDateTime,
}

#[derive(Serialize)]
struct IndexContext {
    projects: Projects,
}

#[derive(Serialize)]
struct NoteContext {
    projects: Projects,
    selected_project: Option<String>,
}

#[derive(Serialize)]
struct NotesContext {
    title: String,
    add_note: Option<String>,
    formatted_notes: String,
}

#[derive(FromForm,Debug)]
struct NotesForm {
    project: String,
    note: String,
}

#[derive(FromForm,Debug,Default)]
struct PageOptions {
    raw: Option<bool>,
}

fn main() {
    rocket::ignite()
        .mount("/",
               routes![webapp_index,
                       webapp_timeline,
                       webapp_notes_all,
                       webapp_notes,
                       webapp_notes_legacy,
                       webapp_note,
                       webapp_note_project,
                       webapp_note_add,
                       webapp_static])
        .launch();
}

#[get("/")]
fn webapp_index() -> Template {
    let datadir = get_datadir();
    let projects = get_projects(&datadir, None);
    let context = IndexContext { projects: projects };

    Template::render("index", &context)
}

#[get("/timeline")]
fn webapp_timeline() -> Template {
    let datadir = get_datadir();
    let formatted = format_or_cached_git(get_timeline, None, &datadir, Some("_timeline"), false);

    let context = NotesContext {
        title: String::from("Timeline"),
        add_note: None,
        formatted_notes: formatted,
    };

    Template::render("notes", &context)
}

#[get("/notes")]
fn webapp_notes_all() -> Template {
    let datadir = get_datadir();
    let formatted = format_or_cached_git(format_notes, None, &datadir, Some("_notes"), false);

    let context = NotesContext {
        title: String::from("All Notes"),
        add_note: None,
        formatted_notes: formatted,
    };

    Template::render("notes", &context)
}

#[get("/notes/<project>")]
fn webapp_notes(project: &str) -> Template {
    let datadir = get_datadir();
    let formatted =
        format_or_cached_modified(format_notes, Some(project), &datadir, Some(project), false);

    let context = NotesContext {
        title: String::from(project),
        add_note: Some(String::from(project)),
        formatted_notes: formatted,
    };

    Template::render("notes", &context)
}

#[get("/show/entries/<project>")]
fn webapp_notes_legacy(project: &str) -> Template {
    let datadir = get_datadir();
    let formatted = match project {
        "_" => format_or_cached_git(format_notes, None, &datadir, Some("_notes"), false),
        _ => format_or_cached_modified(format_notes, Some(project), &datadir, Some(project), false),
    };

    let context = NotesContext {
        title: match project {
            "_" => String::from("All Notes"),
            _ => String::from(project),
        },
        add_note: match project {
            "_" => None,
            _ => Some(String::from(project)),
        },
        formatted_notes: formatted,
    };

    Template::render("notes", &context)
}

#[get("/note")]
fn webapp_note() -> Template {
    let datadir = get_datadir();
    let projects = get_projects(&datadir, None);

    let context = NoteContext {
        projects: projects,
        selected_project: None,
    };

    Template::render("note", &context)
}

#[get("/note/<project>")]
fn webapp_note_project(project: String) -> Template {
    let datadir = get_datadir();
    let projects = get_projects(&datadir, None);

    let context = NoteContext {
        projects: projects,
        selected_project: Some(project),
    };

    Template::render("note", &context)
}

#[post("/note_add", data="<noteform>")]
fn webapp_note_add(noteform: Form<NotesForm>) -> Redirect {
    let note: Note = note_from_form(noteform.get());
    let project = noteform.get().project.as_str();

    let datadir = get_datadir();
    if write_note(&datadir, Some(project), &note).is_some() {
        git_commit_note(&datadir, Some(project), &note)
    }

    if let Err(err) = githelper::sync(datadir.as_path()) {
        warn!("can not sync with repo: {}", err)
    }

    let timestamp = asciidoc_timestamp(format!("{}", note.time_stamp).as_str());
    Redirect::to(format!("/notes/{}#{}", project, timestamp).as_str())
}

#[get("/<path..>", rank = 5)]
fn webapp_static(path: PathBuf) -> io::Result<NamedFile> {
    NamedFile::open(Path::new("static/").join(path))
}

fn asciidoc_timestamp(input: &str) -> String {
    String::from(input).to_lowercase().replace(' ', "-").replace(':', "-").replace('.', "-")
}

#[test]
fn test_asciidoc_timestamp() {
    assert_eq!(asciidoc_timestamp("2016-10-27 15:14:07.704374171 UTC"),
               "2016-10-27-15-14-07-704374171-utc")
}

fn get_datadir() -> PathBuf {
    let conf = config::active().expect("can not get config for reading the datadir");

    let datadir = match conf.get_str("datadir") {
        Ok(config) => PathBuf::from(config),
        Err(_) => {
            let xdg = BaseDirectories::new()
                .expect("can not create new xdg context for creating the datadir");
            xdg.create_data_directory("lablog").expect("can not create new datadir directory")
        }
    };

    debug!("datadir: {:#?}", datadir);

    datadir
}

fn format_or_cached_modified(format: fn(Project, &PathBuf) -> String,
                             project: Project,
                             datadir: &PathBuf,
                             cachefile: Project,
                             raw: bool)
                             -> String {
    if raw {
        return format(project, datadir);
    }

    match cache_find_file(cachefile) {
        None => {
            debug!("no cachefile will generate new file");
            get_projects_asiidoc_write_cache(format, project, datadir, &cache_place_file(cachefile))
        }
        Some(path) => {
            let data = file_to_string(&path).expect("can not read cache file");
            let decoded: HTMLCache = json::decode(data.as_str())
                .expect("can not decode cache file");

            let mut project_path = datadir.clone();
            project_path.push(normalize_project_path(project, "csv"));
            trace!("project_path: {:#?}", project_path);

            let metadata = File::open(&project_path)
                .expect("can not open file of cachefile to read metadata")
                .metadata()
                .expect("can not read metadata from cachefile");

            let mtime = metadata.mtime();
            let mtime_nsec = metadata.mtime_nsec() as u32;

            trace!("mtime: {}", mtime);
            trace!("mtime_nsec: {}", mtime_nsec);

            let file_modified = NaiveDateTime::from_timestamp(mtime, mtime_nsec);

            trace!("file modified: {:#?}", file_modified);
            trace!("cache modified: {:#?}", decoded.modified);

            if file_modified <= decoded.modified {
                debug!("serve cachefile");
                decoded.html
            } else {
                debug!("file_modified is newer than decoded.modified");
                get_projects_asiidoc_write_cache(format, project, datadir, &path)
            }
        }
    }
}

fn format_or_cached_git(format: fn(Project, &PathBuf) -> String,
                        project: Project,
                        datadir: &PathBuf,
                        cachefile: Project,
                        raw: bool)
                        -> String {
    if raw {
        return format(project, datadir);
    }

    match cache_find_file(cachefile) {
        None => {
            debug!("no cachefile will generate new file");
            get_projects_asiidoc_write_cache(format, project, datadir, &cache_place_file(cachefile))
        }
        Some(path) => {
            let data = file_to_string(&path).expect("can not read data from cached git file");
            let decoded: HTMLCache = json::decode(data.as_str())
                .expect("can not decode data of a git cache file");

            let gitcommit = githelper::get_current_commitid_for_repo(datadir)
                .expect("can not get the current git commit for a git cache file");
            if gitcommit == decoded.gitcommit {
                debug!("serve cachefile");
                decoded.html
            } else {
                debug!("commits different will generate new file");
                get_projects_asiidoc_write_cache(format, project, datadir, &path)
            }
        }
    }
}

fn get_projects_asiidoc_write_cache(format: fn(Project, &PathBuf) -> String,
                                    project: Project,
                                    datadir: &PathBuf,
                                    cachefile: &PathBuf)
                                    -> String {
    let asciidoc = format(project, datadir);
    let out = format_asciidoc(asciidoc);

    let modified = match project {
        Some(_) => {
            let mut project_path = datadir.clone();
            project_path.push(normalize_project_path(project, "csv"));

            let (mtime, mtime_nsec) = match File::open(&project_path) {
                Ok(file) => {
                    match file.metadata() {
                        Ok(metadata) => (metadata.mtime(), metadata.mtime_nsec() as u32),
                        Err(_) => (0, 0),
                    }
                }
                Err(_) => (0, 0),
            };

            debug!("project file mtime: {}", mtime);
            debug!("project file mtime_nsec: {}", mtime_nsec);
            NaiveDateTime::from_timestamp(mtime, mtime_nsec)
        }
        None => NaiveDateTime::from_timestamp(0, 0),
    };

    debug!("cachefile put: {:#?}", cachefile);

    let cache = HTMLCache {
        gitcommit: githelper::get_current_commitid_for_repo(datadir)
            .expect("can not get current commit for writing to cachefile"),
        html: out.clone(),
        modified: modified,
    };

    let encoded = json::encode(&cache).expect("can not encode cachefile");
    let mut file = File::create(cachefile).expect("can not create cachefile");
    file.write_all(encoded.as_bytes()).expect("can not write to cachefile");

    out
}

fn note_from_form(form: &NotesForm) -> Note {
    Note {
        time_stamp: UTC::now().into(),
        value: form.note.clone(),
    }
}

fn format_asciidoc(input: String) -> String {
    let tmpdir = TempDir::new("lablog-web_tmp")
        .expect("can not create a new tmpdir for asciiformatting");
    let tmppath = tmpdir.path().join("output.asciidoc");
    let mut file = File::create(&tmppath).expect("can not create a new file for asciiformatting");
    file.write_all(input.as_bytes()).expect("can not write to asciiformatting file");

    let output = Command::new("asciidoctor")
        .arg("--safe-mode")
        .arg("safe")
        .arg("--no-header-footer")
        .arg("--out-file")
        .arg("-")
        .arg(tmppath)
        .output()
        .expect("problems while running asciidoctor");

    debug!("status: {}", output.status);
    debug!("stdout: {}", String::from_utf8_lossy(&output.stdout));
    debug!("stderr: {}", String::from_utf8_lossy(&output.stderr));

    String::from_utf8_lossy(&output.stdout).into_owned()
}

fn cache_find_file(project: Project) -> Option<PathBuf> {
    let xdg = BaseDirectories::new().expect("can not get new xdg context for finding a cachefile");
    let mut cache_path = PathBuf::from("lablog-web");
    cache_path.push(normalize_project_path(project, "cache"));

    let cachefile = xdg.find_cache_file(&cache_path);
    debug!("found cachefile: {:#?} from project {:#?}",
           cachefile,
           project);

    cachefile
}

fn cache_place_file(project: Project) -> PathBuf {
    let xdg = BaseDirectories::new()
        .expect("can not open a new xdg context for writing a cachefile");
    let mut cache_path = PathBuf::from("lablog-web");
    cache_path.push(normalize_project_path(project, "cache"));
    let cachefile = xdg.place_cache_file(&cache_path).expect("can not place a new cachefile");

    debug!("put cachefile: {:#?} from project {:#?}",
           cachefile,
           project);

    cachefile
}
<|endoftext|>


<commit_before>use crate::utils::{any_parent_is_automatically_derived, contains_name, match_def_path, paths, qpath_res, snippet};
use crate::utils::{span_lint_and_note, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Adt, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for literal calls to `Default::default()`.
    ///
    /// **Why is this bad?** It's more clear to the reader to use the name of the type whose default is
    /// being gotten than the generic `Default`.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// // Bad
    /// let s: String = Default::default();
    ///
    /// // Good
    /// let s = String::default();
    /// ```
    pub DEFAULT_TRAIT_ACCESS,
    pedantic,
    "checks for literal calls to `Default::default()`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for immediate reassignment of fields initialized
    /// with Default::default().
    ///
    /// **Why is this bad?**It's more idiomatic to use the [functional update syntax](https://doc.rust-lang.org/reference/expressions/struct-expr.html#functional-update-syntax).
    ///
    /// **Known problems:** Assignments to patterns that are of tuple type are not linted.
    ///
    /// **Example:**
    /// Bad:
    /// ```
    /// # #[derive(Default)]
    /// # struct A { i: i32 }
    /// let mut a: A = Default::default();
    /// a.i = 42;
    /// ```
    /// Use instead:
    /// ```
    /// # #[derive(Default)]
    /// # struct A { i: i32 }
    /// let a = A {
    ///     i: 42,
    ///     .. Default::default()
    /// };
    /// ```
    pub FIELD_REASSIGN_WITH_DEFAULT,
    style,
    "binding initialized with Default should have its fields set in the initializer"
}

#[derive(Default)]
pub struct Default {
    // Spans linted by `field_reassign_with_default`.
    reassigned_linted: FxHashSet<Span>,
}

impl_lint_pass!(Default => [DEFAULT_TRAIT_ACCESS, FIELD_REASSIGN_WITH_DEFAULT]);

impl LateLintPass<'_> for Default {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        if_chain! {
            // Avoid cases already linted by `field_reassign_with_default`
            if !self.reassigned_linted.contains(&expr.span);
            if let ExprKind::Call(ref path, ..) = expr.kind;
            if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id);
            if let ExprKind::Path(ref qpath) = path.kind;
            if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
            if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
            // Detect and ignore <Foo as Default>::default() because these calls do explicitly name the type.
            if let QPath::Resolved(None, _path) = qpath;
            then {
                let expr_ty = cx.typeck_results().expr_ty(expr);
                if let ty::Adt(def, ..) = expr_ty.kind() {
                    // TODO: Work out a way to put "whatever the imported way of referencing
                    // this type in this file" rather than a fully-qualified type.
                    let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did));
                    span_lint_and_sugg(
                        cx,
                        DEFAULT_TRAIT_ACCESS,
                        expr.span,
                        &format!("calling `{}` is more clear than this expression", replacement),
                        "try",
                        replacement,
                        Applicability::Unspecified, // First resolve the TODO above
                    );
                }
            }
        }
    }

    fn check_block<'tcx>(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
        // find all binding statements like `let mut _ = T::default()` where `T::default()` is the
        // `default` method of the `Default` trait, and store statement index in current block being
        // checked and the name of the bound variable
        let binding_statements_using_default = enumerate_bindings_using_default(cx, block);

        // start from the `let mut _ = _::default();` and look at all the following
        // statements, see if they re-assign the fields of the binding
        for (stmt_idx, binding_name, binding_type, span) in binding_statements_using_default {
            // the last statement of a block cannot trigger the lint
            if stmt_idx == block.stmts.len() - 1 {
                break;
            }

            // find all "later statement"'s where the fields of the binding set as
            // Default::default() get reassigned, unless the reassignment refers to the original binding
            let mut first_assign = None;
            let mut assigned_fields = Vec::new();
            let mut cancel_lint = false;
            for consecutive_statement in &block.stmts[stmt_idx + 1..] {
                // interrupt if the statement is a let binding (`Local`) that shadows the original
                // binding
                if stmt_shadows_binding(consecutive_statement, binding_name) {
                    break;
                }
                // find out if and which field was set by this `consecutive_statement`
                else if let Some((field_ident, assign_rhs)) =
                    field_reassigned_by_stmt(consecutive_statement, binding_name)
                {
                    // interrupt and cancel lint if assign_rhs references the original binding
                    if contains_name(binding_name, assign_rhs) {
                        cancel_lint = true;
                        break;
                    }

                    // if the field was previously assigned, replace the assignment, otherwise insert the assignment
                    if let Some(prev) = assigned_fields
                        .iter_mut()
                        .find(|(field_name, _)| field_name == &field_ident.name)
                    {
                        *prev = (field_ident.name, assign_rhs);
                    } else {
                        assigned_fields.push((field_ident.name, assign_rhs));
                    }

                    // also set first instance of error for help message
                    if first_assign.is_none() {
                        first_assign = Some(consecutive_statement);
                    }
                }
                // interrupt also if no field was assigned, since we only want to look at consecutive statements
                else {
                    break;
                }
            }

            // if there are incorrectly assigned fields, do a span_lint_and_note to suggest
            // construction using `Ty { fields, ..Default::default() }`
            if !assigned_fields.is_empty() && !cancel_lint {
                // take the original assignment as span
                let stmt = &block.stmts[stmt_idx];

                if let StmtKind::Local(preceding_local) = &stmt.kind {
                    // if all fields of the struct are not assigned, add `.. Default::default()` to the suggestion.
                    let ext_with_default = !fields_of_type(binding_type)
                        .iter()
                        .all(|field| assigned_fields.iter().any(|(a, _)| a == &field.name));

                    let field_list = assigned_fields
                        .into_iter()
                        .map(|(field, rhs)| {
                            // extract and store the assigned value for help message
                            let value_snippet = snippet(cx, rhs.span, "..");
                            format!("{}: {}", field, value_snippet)
                        })
                        .collect::<Vec<String>>()
                        .join(", ");

                    let sugg = if ext_with_default {
                        if field_list.is_empty() {
                            format!("{}::default()", binding_type)
                        } else {
                            format!("{} {{ {}, ..Default::default() }}", binding_type, field_list)
                        }
                    } else {
                        format!("{} {{ {} }}", binding_type, field_list)
                    };

                    // span lint once per statement that binds default
                    span_lint_and_note(
                        cx,
                        FIELD_REASSIGN_WITH_DEFAULT,
                        first_assign.unwrap().span,
                        "field assignment outside of initializer for an instance created with Default::default()",
                        Some(preceding_local.span),
                        &format!(
                            "consider initializing the variable with `{}` and removing relevant reassignments",
                            sugg
                        ),
                    );
                    self.reassigned_linted.insert(span);
                }
            }
        }
    }
}

/// Checks if the given expression is the `default` method belonging to the `Default` trait.
fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool {
    if_chain! {
        if let ExprKind::Call(ref fn_expr, _) = &expr.kind;
        if let ExprKind::Path(qpath) = &fn_expr.kind;
        if let Res::Def(_, def_id) = qpath_res(cx, qpath, fn_expr.hir_id);
        then {
            // right hand side of assignment is `Default::default`
            match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD)
        } else {
            false
        }
    }
}

/// Returns the block indices, identifiers and types of bindings set as `Default::default()`, except
/// for when the pattern type is a tuple.
fn enumerate_bindings_using_default<'tcx>(
    cx: &LateContext<'tcx>,
    block: &Block<'tcx>,
) -> Vec<(usize, Symbol, Ty<'tcx>, Span)> {
    block
        .stmts
        .iter()
        .enumerate()
        .filter_map(|(idx, stmt)| {
            if_chain! {
                // only take `let ...` statements
                if let StmtKind::Local(ref local) = stmt.kind;
                // only take bindings to identifiers
                if let PatKind::Binding(_, _, ident, _) = local.pat.kind;
                // that are not tuples
                let ty = cx.typeck_results().pat_ty(local.pat);
                if !matches!(ty.kind(), ty::Tuple(_));
                // only when assigning `... = Default::default()`
                if let Some(ref expr) = local.init;
                if is_expr_default(expr, cx);
                then {
                    Some((idx, ident.name, ty, expr.span))
                } else {
                    None
                }
            }
        })
        .collect()
}

fn stmt_shadows_binding(this: &Stmt<'_>, shadowed: Symbol) -> bool {
    if let StmtKind::Local(local) = &this.kind {
        if let PatKind::Binding(_, _, ident, _) = local.pat.kind {
            return ident.name == shadowed;
        }
    }
    false
}

/// Returns the reassigned field and the assigning expression (right-hand side of assign).
fn field_reassigned_by_stmt<'tcx>(this: &Stmt<'tcx>, binding_name: Symbol) -> Option<(Ident, &'tcx Expr<'tcx>)> {
    if_chain! {
        // only take assignments
        if let StmtKind::Semi(ref later_expr) = this.kind;
        if let ExprKind::Assign(ref assign_lhs, ref assign_rhs, _) = later_expr.kind;
        // only take assignments to fields where the left-hand side field is a field of
        // the same binding as the previous statement
        if let ExprKind::Field(ref binding, field_ident) = assign_lhs.kind;
        if let ExprKind::Path(QPath::Resolved(_, path)) = binding.kind;
        if let Some(second_binding_name) = path.segments.last();
        if second_binding_name.ident.name == binding_name;
        then {
            Some((field_ident, assign_rhs))
        } else {
            None
        }
    }
}

/// Returns the vec of fields for a struct and an empty vec for non-struct ADTs.
fn fields_of_type(ty: Ty<'_>) -> Vec<Ident> {
    if let Adt(adt, _) = ty.kind() {
        if adt.is_struct() {
            let variant = &adt.non_enum_variant();
            return variant.fields.iter().map(|f| f.ident).collect();
        }
    }
    vec![]
}
<commit_msg>Remove redundant shadow check<commit_after>use crate::utils::{any_parent_is_automatically_derived, contains_name, match_def_path, paths, qpath_res, snippet};
use crate::utils::{span_lint_and_note, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Adt, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for literal calls to `Default::default()`.
    ///
    /// **Why is this bad?** It's more clear to the reader to use the name of the type whose default is
    /// being gotten than the generic `Default`.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// // Bad
    /// let s: String = Default::default();
    ///
    /// // Good
    /// let s = String::default();
    /// ```
    pub DEFAULT_TRAIT_ACCESS,
    pedantic,
    "checks for literal calls to `Default::default()`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for immediate reassignment of fields initialized
    /// with Default::default().
    ///
    /// **Why is this bad?**It's more idiomatic to use the [functional update syntax](https://doc.rust-lang.org/reference/expressions/struct-expr.html#functional-update-syntax).
    ///
    /// **Known problems:** Assignments to patterns that are of tuple type are not linted.
    ///
    /// **Example:**
    /// Bad:
    /// ```
    /// # #[derive(Default)]
    /// # struct A { i: i32 }
    /// let mut a: A = Default::default();
    /// a.i = 42;
    /// ```
    /// Use instead:
    /// ```
    /// # #[derive(Default)]
    /// # struct A { i: i32 }
    /// let a = A {
    ///     i: 42,
    ///     .. Default::default()
    /// };
    /// ```
    pub FIELD_REASSIGN_WITH_DEFAULT,
    style,
    "binding initialized with Default should have its fields set in the initializer"
}

#[derive(Default)]
pub struct Default {
    // Spans linted by `field_reassign_with_default`.
    reassigned_linted: FxHashSet<Span>,
}

impl_lint_pass!(Default => [DEFAULT_TRAIT_ACCESS, FIELD_REASSIGN_WITH_DEFAULT]);

impl LateLintPass<'_> for Default {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        if_chain! {
            // Avoid cases already linted by `field_reassign_with_default`
            if !self.reassigned_linted.contains(&expr.span);
            if let ExprKind::Call(ref path, ..) = expr.kind;
            if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id);
            if let ExprKind::Path(ref qpath) = path.kind;
            if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
            if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
            // Detect and ignore <Foo as Default>::default() because these calls do explicitly name the type.
            if let QPath::Resolved(None, _path) = qpath;
            then {
                let expr_ty = cx.typeck_results().expr_ty(expr);
                if let ty::Adt(def, ..) = expr_ty.kind() {
                    // TODO: Work out a way to put "whatever the imported way of referencing
                    // this type in this file" rather than a fully-qualified type.
                    let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did));
                    span_lint_and_sugg(
                        cx,
                        DEFAULT_TRAIT_ACCESS,
                        expr.span,
                        &format!("calling `{}` is more clear than this expression", replacement),
                        "try",
                        replacement,
                        Applicability::Unspecified, // First resolve the TODO above
                    );
                }
            }
        }
    }

    fn check_block<'tcx>(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
        // find all binding statements like `let mut _ = T::default()` where `T::default()` is the
        // `default` method of the `Default` trait, and store statement index in current block being
        // checked and the name of the bound variable
        let binding_statements_using_default = enumerate_bindings_using_default(cx, block);

        // start from the `let mut _ = _::default();` and look at all the following
        // statements, see if they re-assign the fields of the binding
        for (stmt_idx, binding_name, binding_type, span) in binding_statements_using_default {
            // the last statement of a block cannot trigger the lint
            if stmt_idx == block.stmts.len() - 1 {
                break;
            }

            // find all "later statement"'s where the fields of the binding set as
            // Default::default() get reassigned, unless the reassignment refers to the original binding
            let mut first_assign = None;
            let mut assigned_fields = Vec::new();
            let mut cancel_lint = false;
            for consecutive_statement in &block.stmts[stmt_idx + 1..] {
                // find out if and which field was set by this `consecutive_statement`
                if let Some((field_ident, assign_rhs)) = field_reassigned_by_stmt(consecutive_statement, binding_name) {
                    // interrupt and cancel lint if assign_rhs references the original binding
                    if contains_name(binding_name, assign_rhs) {
                        cancel_lint = true;
                        break;
                    }

                    // if the field was previously assigned, replace the assignment, otherwise insert the assignment
                    if let Some(prev) = assigned_fields
                        .iter_mut()
                        .find(|(field_name, _)| field_name == &field_ident.name)
                    {
                        *prev = (field_ident.name, assign_rhs);
                    } else {
                        assigned_fields.push((field_ident.name, assign_rhs));
                    }

                    // also set first instance of error for help message
                    if first_assign.is_none() {
                        first_assign = Some(consecutive_statement);
                    }
                }
                // interrupt if no field was assigned, since we only want to look at consecutive statements
                else {
                    break;
                }
            }

            // if there are incorrectly assigned fields, do a span_lint_and_note to suggest
            // construction using `Ty { fields, ..Default::default() }`
            if !assigned_fields.is_empty() && !cancel_lint {
                // take the original assignment as span
                let stmt = &block.stmts[stmt_idx];

                if let StmtKind::Local(preceding_local) = &stmt.kind {
                    // if all fields of the struct are not assigned, add `.. Default::default()` to the suggestion.
                    let ext_with_default = !fields_of_type(binding_type)
                        .iter()
                        .all(|field| assigned_fields.iter().any(|(a, _)| a == &field.name));

                    let field_list = assigned_fields
                        .into_iter()
                        .map(|(field, rhs)| {
                            // extract and store the assigned value for help message
                            let value_snippet = snippet(cx, rhs.span, "..");
                            format!("{}: {}", field, value_snippet)
                        })
                        .collect::<Vec<String>>()
                        .join(", ");

                    let sugg = if ext_with_default {
                        if field_list.is_empty() {
                            format!("{}::default()", binding_type)
                        } else {
                            format!("{} {{ {}, ..Default::default() }}", binding_type, field_list)
                        }
                    } else {
                        format!("{} {{ {} }}", binding_type, field_list)
                    };

                    // span lint once per statement that binds default
                    span_lint_and_note(
                        cx,
                        FIELD_REASSIGN_WITH_DEFAULT,
                        first_assign.unwrap().span,
                        "field assignment outside of initializer for an instance created with Default::default()",
                        Some(preceding_local.span),
                        &format!(
                            "consider initializing the variable with `{}` and removing relevant reassignments",
                            sugg
                        ),
                    );
                    self.reassigned_linted.insert(span);
                }
            }
        }
    }
}

/// Checks if the given expression is the `default` method belonging to the `Default` trait.
fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool {
    if_chain! {
        if let ExprKind::Call(ref fn_expr, _) = &expr.kind;
        if let ExprKind::Path(qpath) = &fn_expr.kind;
        if let Res::Def(_, def_id) = qpath_res(cx, qpath, fn_expr.hir_id);
        then {
            // right hand side of assignment is `Default::default`
            match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD)
        } else {
            false
        }
    }
}

/// Returns the block indices, identifiers and types of bindings set as `Default::default()`, except
/// for when the pattern type is a tuple.
fn enumerate_bindings_using_default<'tcx>(
    cx: &LateContext<'tcx>,
    block: &Block<'tcx>,
) -> Vec<(usize, Symbol, Ty<'tcx>, Span)> {
    block
        .stmts
        .iter()
        .enumerate()
        .filter_map(|(idx, stmt)| {
            if_chain! {
                // only take `let ...` statements
                if let StmtKind::Local(ref local) = stmt.kind;
                // only take bindings to identifiers
                if let PatKind::Binding(_, _, ident, _) = local.pat.kind;
                // that are not tuples
                let ty = cx.typeck_results().pat_ty(local.pat);
                if !matches!(ty.kind(), ty::Tuple(_));
                // only when assigning `... = Default::default()`
                if let Some(ref expr) = local.init;
                if is_expr_default(expr, cx);
                then {
                    Some((idx, ident.name, ty, expr.span))
                } else {
                    None
                }
            }
        })
        .collect()
}

/// Returns the reassigned field and the assigning expression (right-hand side of assign).
fn field_reassigned_by_stmt<'tcx>(this: &Stmt<'tcx>, binding_name: Symbol) -> Option<(Ident, &'tcx Expr<'tcx>)> {
    if_chain! {
        // only take assignments
        if let StmtKind::Semi(ref later_expr) = this.kind;
        if let ExprKind::Assign(ref assign_lhs, ref assign_rhs, _) = later_expr.kind;
        // only take assignments to fields where the left-hand side field is a field of
        // the same binding as the previous statement
        if let ExprKind::Field(ref binding, field_ident) = assign_lhs.kind;
        if let ExprKind::Path(QPath::Resolved(_, path)) = binding.kind;
        if let Some(second_binding_name) = path.segments.last();
        if second_binding_name.ident.name == binding_name;
        then {
            Some((field_ident, assign_rhs))
        } else {
            None
        }
    }
}

/// Returns the vec of fields for a struct and an empty vec for non-struct ADTs.
fn fields_of_type(ty: Ty<'_>) -> Vec<Ident> {
    if let Adt(adt, _) = ty.kind() {
        if adt.is_struct() {
            let variant = &adt.non_enum_variant();
            return variant.fields.iter().map(|f| f.ident).collect();
        }
    }
    vec![]
}
<|endoftext|>


<commit_before>use pyo3::ffi::{Py_hash_t, Py_intptr_t, Py_uintptr_t};
use std::os::raw::*;

pub type npy_intp = Py_intptr_t;
pub type npy_uintp = Py_uintptr_t;
pub type npy_longlong = c_longlong;
pub type npy_ulonglong = c_ulonglong;
pub type npy_bool = c_uchar;
pub type npy_longdouble = f64;
pub type npy_byte = c_char;
pub type npy_ubyte = c_uchar;
pub type npy_ushort = c_ushort;
pub type npy_uint = c_uint;
pub type npy_ulong = c_ulong;
pub type npy_char = c_char;
pub type npy_short = c_short;
pub type npy_int = c_int;
pub type npy_long = c_long;
pub type npy_float = f32;
pub type npy_double = f64;
pub type npy_hash_t = Py_hash_t;
pub type npy_int64 = c_long;
pub type npy_uint64 = c_ulong;
pub type npy_int32 = c_int;
pub type npy_uint32 = c_uint;
pub type npy_ucs4 = c_uint;
pub type npy_int16 = c_short;
pub type npy_uint16 = c_ushort;
pub type npy_int8 = c_char;
pub type npy_uint8 = c_uchar;
pub type npy_float64 = f64;
pub type npy_complex128 = npy_cdouble;
pub type npy_float32 = f32;
pub type npy_complex64 = npy_cfloat;
pub type npy_half = npy_uint16;
pub type npy_float16 = npy_half;
pub type npy_float128 = npy_longdouble;
pub type npy_complex256 = npy_clongdouble;
pub type npy_timedelta = npy_int64;
pub type npy_datetime = npy_int64;

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct npy_cdouble {
    pub real: f64,
    pub imag: f64,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct npy_cfloat {
    pub real: f32,
    pub imag: f32,
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct npy_clongdouble {
    pub real: npy_longdouble,
    pub imag: npy_longdouble,
}

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum NPY_ORDER {
    NPY_ANYORDER = -1,
    NPY_CORDER = 0,
    NPY_FORTRANORDER = 1,
    NPY_KEEPORDER = 2,
}

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum NPY_SCALARKIND {
    NPY_NOSCALAR = -1,
    NPY_BOOL_SCALAR = 0,
    NPY_INTPOS_SCALAR = 1,
    NPY_INTNEG_SCALAR = 2,
    NPY_FLOAT_SCALAR = 3,
    NPY_COMPLEX_SCALAR = 4,
    NPY_OBJECT_SCALAR = 5,
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum NPY_SORTKIND {
    NPY_QUICKSORT = 0,
    NPY_HEAPSORT = 1,
    NPY_MERGESORT = 2,
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum NPY_SEARCHSIDE {
    NPY_SEARCHLEFT = 0,
    NPY_SEARCHRIGHT = 1,
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum NPY_DATETIMEUNIT {
    NPY_FR_Y = 0,
    NPY_FR_M = 1,
    NPY_FR_W = 2,
    NPY_FR_D = 4,
    NPY_FR_h = 5,
    NPY_FR_m = 6,
    NPY_FR_s = 7,
    NPY_FR_ms = 8,
    NPY_FR_us = 9,
    NPY_FR_ns = 10,
    NPY_FR_ps = 11,
    NPY_FR_fs = 12,
    NPY_FR_as = 13,
    NPY_FR_GENERIC = 14,
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum NPY_TYPES {
    NPY_BOOL = 0,
    NPY_BYTE = 1,
    NPY_UBYTE = 2,
    NPY_SHORT = 3,
    NPY_USHORT = 4,
    NPY_INT = 5,
    NPY_UINT = 6,
    NPY_LONG = 7,
    NPY_ULONG = 8,
    NPY_LONGLONG = 9,
    NPY_ULONGLONG = 10,
    NPY_FLOAT = 11,
    NPY_DOUBLE = 12,
    NPY_LONGDOUBLE = 13,
    NPY_CFLOAT = 14,
    NPY_CDOUBLE = 15,
    NPY_CLONGDOUBLE = 16,
    NPY_OBJECT = 17,
    NPY_STRING = 18,
    NPY_UNICODE = 19,
    NPY_VOID = 20,
    NPY_DATETIME = 21,
    NPY_TIMEDELTA = 22,
    NPY_HALF = 23,
    NPY_NTYPES = 24,
    NPY_NOTYPE = 25,
    NPY_CHAR = 26,
    NPY_USERDEF = 256,
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum NPY_SELECTKIND {
    NPY_INTROSELECT = 0,
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum NPY_CASTING {
    NPY_NO_CASTING = 0,
    NPY_EQUIV_CASTING = 1,
    NPY_SAFE_CASTING = 2,
    NPY_SAME_KIND_CASTING = 3,
    NPY_UNSAFE_CASTING = 4,
}

#[repr(u32)]
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum NPY_CLIPMODE {
    NPY_CLIP = 0,
    NPY_WRAP = 1,
    NPY_RAISE = 2,
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct npy_datetimestruct {
    pub year: npy_int64,
    pub month: npy_int32,
    pub day: npy_int32,
    pub hour: npy_int32,
    pub min: npy_int32,
    pub sec: npy_int32,
    pub us: npy_int32,
    pub ps: npy_int32,
    pub as_: npy_int32,
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct npy_timedeltastruct {
    pub day: npy_int64,
    pub sec: npy_int32,
    pub us: npy_int32,
    pub ps: npy_int32,
    pub as_: npy_int32,
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct npy_stride_sort_item {
    pub perm: npy_intp,
    pub stride: npy_intp,
}

#[repr(u8)]
#[derive(Debug, Clone, Copy)]
pub enum NPY_TYPECHAR {
    NPY_BOOLLTR = b'?',
    NPY_BYTELTR = b'b',
    NPY_UBYTELTR = b'B',
    NPY_SHORTLTR = b'h',
    NPY_USHORTLTR = b'H',
    NPY_INTLTR = b'i',
    NPY_UINTLTR = b'I',
    NPY_LONGLTR = b'l',
    NPY_ULONGLTR = b'L',
    NPY_LONGLONGLTR = b'q',
    NPY_ULONGLONGLTR = b'Q',
    NPY_HALFLTR = b'e',
    NPY_FLOATLTR = b'f',
    NPY_DOUBLELTR = b'd',
    NPY_LONGDOUBLELTR = b'g',
    NPY_CFLOATLTR = b'F',
    NPY_CDOUBLELTR = b'D',
    NPY_CLONGDOUBLELTR = b'G',
    NPY_OBJECTLTR = b'O',
    NPY_STRINGLTR = b'S',
    NPY_STRINGLTR2 = b'a',
    NPY_UNICODELTR = b'U',
    NPY_VOIDLTR = b'V',
    NPY_DATETIMELTR = b'M',
    NPY_TIMEDELTALTR = b'm',
    NPY_CHARLTR = b'c',
    NPY_INTPLTR = b'p',
    NPY_UINTPLTR = b'P',
}

#[repr(u8)]
#[derive(Debug, Clone, Copy)]
// NPY_TYPEKINDCHAR doesn't exist in the header, but these enum values are not
// related to NPY_TYPECHAR although being stuffed into it (type kinds, not type codes)
pub enum NPY_TYPEKINDCHAR {
    NPY_GENBOOLLTR = b'b',
    NPY_SIGNEDLTR = b'i',
    NPY_UNSIGNEDLTR = b'u',
    NPY_FLOATINGLTR = b'f',
    NPY_COMPLEXLTR = b'c',
}

#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum NPY_BYTEORDER_CHAR {
    NPY_LITTLE = b'<',
    NPY_BIG = b'>',
    NPY_NATIVE = b'=',
    NPY_SWAP = b's',
    NPY_IGNORE = b'|',
}

impl NPY_BYTEORDER_CHAR {
    #[cfg(target_endian = "little")]
    pub const NPY_NATBYTE: Self = Self::NPY_LITTLE;
    #[cfg(target_endian = "little")]
    pub const NPY_OPPBYTE: Self = Self::NPY_BIG;

    #[cfg(target_endian = "big")]
    pub const NPY_NATBYTE: Self = Self::NPY_BIG;
    #[cfg(target_endian = "big")]
    pub const NPY_OPPBYTE: Self = Self::NPY_LITTLE;
}
<commit_msg>Derive PartialOrd/Ord for NPY_TYPES<commit_after>use pyo3::ffi::{Py_hash_t, Py_intptr_t, Py_uintptr_t};
use std::os::raw::*;

pub type npy_intp = Py_intptr_t;
pub type npy_uintp = Py_uintptr_t;
pub type npy_longlong = c_longlong;
pub type npy_ulonglong = c_ulonglong;
pub type npy_bool = c_uchar;
pub type npy_longdouble = f64;
pub type npy_byte = c_char;
pub type npy_ubyte = c_uchar;
pub type npy_ushort = c_ushort;
pub type npy_uint = c_uint;
pub type npy_ulong = c_ulong;
pub type npy_char = c_char;
pub type npy_short = c_short;
pub type npy_int = c_int;
pub type npy_long = c_long;
pub type npy_float = f32;
pub type npy_double = f64;
pub type npy_hash_t = Py_hash_t;
pub type npy_int64 = c_long;
pub type npy_uint64 = c_ulong;
pub type npy_int32 = c_int;
pub type npy_uint32 = c_uint;
pub type npy_ucs4 = c_uint;
pub type npy_int16 = c_short;
pub type npy_uint16 = c_ushort;
pub type npy_int8 = c_char;
pub type npy_uint8 = c_uchar;
pub type npy_float64 = f64;
pub type npy_complex128 = npy_cdouble;
pub type npy_float32 = f32;
pub type npy_complex64 = npy_cfloat;
pub type npy_half = npy_uint16;
pub type npy_float16 = npy_half;
pub type npy_float128 = npy_longdouble;
pub type npy_complex256 = npy_clongdouble;
pub type npy_timedelta = npy_int64;
pub type npy_datetime = npy_int64;

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct npy_cdouble {
    pub real: f64,
    pub imag: f64,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct npy_cfloat {
    pub real: f32,
    pub imag: f32,
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct npy_clongdouble {
    pub real: npy_longdouble,
    pub imag: npy_longdouble,
}

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum NPY_ORDER {
    NPY_ANYORDER = -1,
    NPY_CORDER = 0,
    NPY_FORTRANORDER = 1,
    NPY_KEEPORDER = 2,
}

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum NPY_SCALARKIND {
    NPY_NOSCALAR = -1,
    NPY_BOOL_SCALAR = 0,
    NPY_INTPOS_SCALAR = 1,
    NPY_INTNEG_SCALAR = 2,
    NPY_FLOAT_SCALAR = 3,
    NPY_COMPLEX_SCALAR = 4,
    NPY_OBJECT_SCALAR = 5,
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum NPY_SORTKIND {
    NPY_QUICKSORT = 0,
    NPY_HEAPSORT = 1,
    NPY_MERGESORT = 2,
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum NPY_SEARCHSIDE {
    NPY_SEARCHLEFT = 0,
    NPY_SEARCHRIGHT = 1,
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum NPY_DATETIMEUNIT {
    NPY_FR_Y = 0,
    NPY_FR_M = 1,
    NPY_FR_W = 2,
    NPY_FR_D = 4,
    NPY_FR_h = 5,
    NPY_FR_m = 6,
    NPY_FR_s = 7,
    NPY_FR_ms = 8,
    NPY_FR_us = 9,
    NPY_FR_ns = 10,
    NPY_FR_ps = 11,
    NPY_FR_fs = 12,
    NPY_FR_as = 13,
    NPY_FR_GENERIC = 14,
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum NPY_TYPES {
    NPY_BOOL = 0,
    NPY_BYTE = 1,
    NPY_UBYTE = 2,
    NPY_SHORT = 3,
    NPY_USHORT = 4,
    NPY_INT = 5,
    NPY_UINT = 6,
    NPY_LONG = 7,
    NPY_ULONG = 8,
    NPY_LONGLONG = 9,
    NPY_ULONGLONG = 10,
    NPY_FLOAT = 11,
    NPY_DOUBLE = 12,
    NPY_LONGDOUBLE = 13,
    NPY_CFLOAT = 14,
    NPY_CDOUBLE = 15,
    NPY_CLONGDOUBLE = 16,
    NPY_OBJECT = 17,
    NPY_STRING = 18,
    NPY_UNICODE = 19,
    NPY_VOID = 20,
    NPY_DATETIME = 21,
    NPY_TIMEDELTA = 22,
    NPY_HALF = 23,
    NPY_NTYPES = 24,
    NPY_NOTYPE = 25,
    NPY_CHAR = 26,
    NPY_USERDEF = 256,
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum NPY_SELECTKIND {
    NPY_INTROSELECT = 0,
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum NPY_CASTING {
    NPY_NO_CASTING = 0,
    NPY_EQUIV_CASTING = 1,
    NPY_SAFE_CASTING = 2,
    NPY_SAME_KIND_CASTING = 3,
    NPY_UNSAFE_CASTING = 4,
}

#[repr(u32)]
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum NPY_CLIPMODE {
    NPY_CLIP = 0,
    NPY_WRAP = 1,
    NPY_RAISE = 2,
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct npy_datetimestruct {
    pub year: npy_int64,
    pub month: npy_int32,
    pub day: npy_int32,
    pub hour: npy_int32,
    pub min: npy_int32,
    pub sec: npy_int32,
    pub us: npy_int32,
    pub ps: npy_int32,
    pub as_: npy_int32,
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct npy_timedeltastruct {
    pub day: npy_int64,
    pub sec: npy_int32,
    pub us: npy_int32,
    pub ps: npy_int32,
    pub as_: npy_int32,
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct npy_stride_sort_item {
    pub perm: npy_intp,
    pub stride: npy_intp,
}

#[repr(u8)]
#[derive(Debug, Clone, Copy)]
pub enum NPY_TYPECHAR {
    NPY_BOOLLTR = b'?',
    NPY_BYTELTR = b'b',
    NPY_UBYTELTR = b'B',
    NPY_SHORTLTR = b'h',
    NPY_USHORTLTR = b'H',
    NPY_INTLTR = b'i',
    NPY_UINTLTR = b'I',
    NPY_LONGLTR = b'l',
    NPY_ULONGLTR = b'L',
    NPY_LONGLONGLTR = b'q',
    NPY_ULONGLONGLTR = b'Q',
    NPY_HALFLTR = b'e',
    NPY_FLOATLTR = b'f',
    NPY_DOUBLELTR = b'd',
    NPY_LONGDOUBLELTR = b'g',
    NPY_CFLOATLTR = b'F',
    NPY_CDOUBLELTR = b'D',
    NPY_CLONGDOUBLELTR = b'G',
    NPY_OBJECTLTR = b'O',
    NPY_STRINGLTR = b'S',
    NPY_STRINGLTR2 = b'a',
    NPY_UNICODELTR = b'U',
    NPY_VOIDLTR = b'V',
    NPY_DATETIMELTR = b'M',
    NPY_TIMEDELTALTR = b'm',
    NPY_CHARLTR = b'c',
    NPY_INTPLTR = b'p',
    NPY_UINTPLTR = b'P',
}

#[repr(u8)]
#[derive(Debug, Clone, Copy)]
// NPY_TYPEKINDCHAR doesn't exist in the header, but these enum values are not
// related to NPY_TYPECHAR although being stuffed into it (type kinds, not type codes)
pub enum NPY_TYPEKINDCHAR {
    NPY_GENBOOLLTR = b'b',
    NPY_SIGNEDLTR = b'i',
    NPY_UNSIGNEDLTR = b'u',
    NPY_FLOATINGLTR = b'f',
    NPY_COMPLEXLTR = b'c',
}

#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum NPY_BYTEORDER_CHAR {
    NPY_LITTLE = b'<',
    NPY_BIG = b'>',
    NPY_NATIVE = b'=',
    NPY_SWAP = b's',
    NPY_IGNORE = b'|',
}

impl NPY_BYTEORDER_CHAR {
    #[cfg(target_endian = "little")]
    pub const NPY_NATBYTE: Self = Self::NPY_LITTLE;
    #[cfg(target_endian = "little")]
    pub const NPY_OPPBYTE: Self = Self::NPY_BIG;

    #[cfg(target_endian = "big")]
    pub const NPY_NATBYTE: Self = Self::NPY_BIG;
    #[cfg(target_endian = "big")]
    pub const NPY_OPPBYTE: Self = Self::NPY_LITTLE;
}
<|endoftext|>