A Rust crate with both `main.rs` and `lib.rs` performing primality checking











up vote
3
down vote

favorite












Introduction



I decided to get my feet wet in Rust by going ahead an implementing a full crate with the tests, documentation, and all other accompanying stuff. This is a toy implementation of a library containing a function that checks whether a given u64 is prime or not.



What I've also done is implement a main.rs in addition to the lib.rs, that produces an executable when the cargo run or cargo build command is issued. So far the toolchain hasn't complained yet. It seems to be working fine, but I seek adivce on the practicality of it.



The organization



Here is the full structure (excluding the target folder):



prime
+- src
| +- lib.rs
| +- main.rs
| +- prime.rs
+- tests
| +- extern_test.rs
+- Cargo.lock
+- Cargo.toml


The files



lib.rs



pub mod prime;


main.rs



pub mod prime;

use std::env;
use std::io::stdin;

fn take_input() {
println!("Prime cheker utility.n=====================n");
loop {
process_single_line();
if user_wants_to_exit() {
break;
}
}
}

fn process_single_line() {
let mut num_str: String = String::new();

println!("Enter the number to check : ");

stdin().read_line(&mut num_str).unwrap();

process_string(num_str.trim());
}

fn user_wants_to_exit() -> bool {
let mut usr_str = String::new();

println!("Do you want to exit? (y/n) : ");
stdin()
.read_line(&mut usr_str)
.expect("Error while reading input.");

let trimmed = usr_str.trim();

trimmed == "y" || trimmed == "Y" || trimmed.to_lowercase() == "yes"
}

fn process_string(num_str: &str) {
let num = num_str.parse::<u64>().expect(INVALID_NUMBER);

println!(
"The integer {} is{} a prime.",
num,
match prime::is_prime(num) {
true => "",
false => " not",
}
);
}

const HELP_TEXT: &str = "USAGE:nn1. primen2. prime [unsigned integer]n";
const INVALID_NUMBER: &str = "Please enter a valid unsigned integer.";

fn main() {
let args: Vec<String> = env::args().collect();
match args.len() {
1 => take_input(),
2 => process_string(args[1].trim()),
_ => {
println!("{}", HELP_TEXT);
}
}
}


prime.rs



/// This function takes a 64-bit unsigned integer and checks if it is a prime.
///
/// If the number is prime, `true` is returned, and vice-versa.
///
/// #Example
///
/// ```rust
/// use prime_util::*;
///
/// let result = prime::is_prime(31);
/// assert_eq!(result, true);
/// ```
pub fn is_prime(num: u64) -> bool {
if num < 2 {
return false;
}
if num == 2 || num == 3 {
return true;
}
// Even numbers and multiples of 3 are eliminated
if num % 2 == 0 || num % 3 == 0 {
return false;
}

// Optimized divisor approach
// First we calculate the maximum limit of iteration
let limit = (num as f64).sqrt() as u64;
// We start the iteration from 5 (2 and 3 have been already tested)
let mut divisor = 5;
// The step alternates between 2 and 4 to keep the divisor of the form
// 6k +/- 1, where k is an integer
let mut step = 2;
while divisor <= limit {
if num % divisor == 0 {
return false;
}
divisor += step;
step = if step == 2 { 4 } else { 2 }
}
true
}


extern_test.rs



extern crate prime_util;

#[cfg(test)]
mod integration_test {
use prime_util::prime;
#[test]
fn small_number_checks() {
assert_eq!(prime::is_prime(11), true);
assert_eq!(prime::is_prime(12), false);
assert_eq!(prime::is_prime(13), true);
}

#[test]
fn large_number_checks() {
assert_eq!(prime::is_prime(179434027), true);
assert_eq!(prime::is_prime(179434029), false);
assert_eq!(prime::is_prime(179434031), false);
assert_eq!(prime::is_prime(179434033), true);
}

#[test]
fn first_10_numbers_tested() {
assert_eq!(prime::is_prime(0), false);
assert_eq!(prime::is_prime(1), false);
assert_eq!(prime::is_prime(2), true);
assert_eq!(prime::is_prime(3), true);
assert_eq!(prime::is_prime(4), false);
assert_eq!(prime::is_prime(5), true);
assert_eq!(prime::is_prime(6), false);
assert_eq!(prime::is_prime(7), true);
assert_eq!(prime::is_prime(8), false);
assert_eq!(prime::is_prime(9), false);
assert_eq!(prime::is_prime(10), false);
}
}


Others



Cargo.toml is the default one. Nothing has been changed.



Topics of interest



I would like to point out some specific areas that I would like to hear advice on (although I always welcome comments on any aspect of the project):




  1. The fact that I have both main.rs and lib.rs. Cargo couldn't care less apparently. Because it executes all tests (even the documentation test) and also executes as a command-line program when cargo run is called (both with and without arguments).

  2. The general quality of the code. I feel it can always be improved and made more Rusty.

  3. The organization of the files and the containing code, and the documentation.

  4. The external tests that I've included. Any additions/modifications necessary?


I reiterate my invitation for general criticism as well.










share|improve this question


























    up vote
    3
    down vote

    favorite












    Introduction



    I decided to get my feet wet in Rust by going ahead an implementing a full crate with the tests, documentation, and all other accompanying stuff. This is a toy implementation of a library containing a function that checks whether a given u64 is prime or not.



    What I've also done is implement a main.rs in addition to the lib.rs, that produces an executable when the cargo run or cargo build command is issued. So far the toolchain hasn't complained yet. It seems to be working fine, but I seek adivce on the practicality of it.



    The organization



    Here is the full structure (excluding the target folder):



    prime
    +- src
    | +- lib.rs
    | +- main.rs
    | +- prime.rs
    +- tests
    | +- extern_test.rs
    +- Cargo.lock
    +- Cargo.toml


    The files



    lib.rs



    pub mod prime;


    main.rs



    pub mod prime;

    use std::env;
    use std::io::stdin;

    fn take_input() {
    println!("Prime cheker utility.n=====================n");
    loop {
    process_single_line();
    if user_wants_to_exit() {
    break;
    }
    }
    }

    fn process_single_line() {
    let mut num_str: String = String::new();

    println!("Enter the number to check : ");

    stdin().read_line(&mut num_str).unwrap();

    process_string(num_str.trim());
    }

    fn user_wants_to_exit() -> bool {
    let mut usr_str = String::new();

    println!("Do you want to exit? (y/n) : ");
    stdin()
    .read_line(&mut usr_str)
    .expect("Error while reading input.");

    let trimmed = usr_str.trim();

    trimmed == "y" || trimmed == "Y" || trimmed.to_lowercase() == "yes"
    }

    fn process_string(num_str: &str) {
    let num = num_str.parse::<u64>().expect(INVALID_NUMBER);

    println!(
    "The integer {} is{} a prime.",
    num,
    match prime::is_prime(num) {
    true => "",
    false => " not",
    }
    );
    }

    const HELP_TEXT: &str = "USAGE:nn1. primen2. prime [unsigned integer]n";
    const INVALID_NUMBER: &str = "Please enter a valid unsigned integer.";

    fn main() {
    let args: Vec<String> = env::args().collect();
    match args.len() {
    1 => take_input(),
    2 => process_string(args[1].trim()),
    _ => {
    println!("{}", HELP_TEXT);
    }
    }
    }


    prime.rs



    /// This function takes a 64-bit unsigned integer and checks if it is a prime.
    ///
    /// If the number is prime, `true` is returned, and vice-versa.
    ///
    /// #Example
    ///
    /// ```rust
    /// use prime_util::*;
    ///
    /// let result = prime::is_prime(31);
    /// assert_eq!(result, true);
    /// ```
    pub fn is_prime(num: u64) -> bool {
    if num < 2 {
    return false;
    }
    if num == 2 || num == 3 {
    return true;
    }
    // Even numbers and multiples of 3 are eliminated
    if num % 2 == 0 || num % 3 == 0 {
    return false;
    }

    // Optimized divisor approach
    // First we calculate the maximum limit of iteration
    let limit = (num as f64).sqrt() as u64;
    // We start the iteration from 5 (2 and 3 have been already tested)
    let mut divisor = 5;
    // The step alternates between 2 and 4 to keep the divisor of the form
    // 6k +/- 1, where k is an integer
    let mut step = 2;
    while divisor <= limit {
    if num % divisor == 0 {
    return false;
    }
    divisor += step;
    step = if step == 2 { 4 } else { 2 }
    }
    true
    }


    extern_test.rs



    extern crate prime_util;

    #[cfg(test)]
    mod integration_test {
    use prime_util::prime;
    #[test]
    fn small_number_checks() {
    assert_eq!(prime::is_prime(11), true);
    assert_eq!(prime::is_prime(12), false);
    assert_eq!(prime::is_prime(13), true);
    }

    #[test]
    fn large_number_checks() {
    assert_eq!(prime::is_prime(179434027), true);
    assert_eq!(prime::is_prime(179434029), false);
    assert_eq!(prime::is_prime(179434031), false);
    assert_eq!(prime::is_prime(179434033), true);
    }

    #[test]
    fn first_10_numbers_tested() {
    assert_eq!(prime::is_prime(0), false);
    assert_eq!(prime::is_prime(1), false);
    assert_eq!(prime::is_prime(2), true);
    assert_eq!(prime::is_prime(3), true);
    assert_eq!(prime::is_prime(4), false);
    assert_eq!(prime::is_prime(5), true);
    assert_eq!(prime::is_prime(6), false);
    assert_eq!(prime::is_prime(7), true);
    assert_eq!(prime::is_prime(8), false);
    assert_eq!(prime::is_prime(9), false);
    assert_eq!(prime::is_prime(10), false);
    }
    }


    Others



    Cargo.toml is the default one. Nothing has been changed.



    Topics of interest



    I would like to point out some specific areas that I would like to hear advice on (although I always welcome comments on any aspect of the project):




    1. The fact that I have both main.rs and lib.rs. Cargo couldn't care less apparently. Because it executes all tests (even the documentation test) and also executes as a command-line program when cargo run is called (both with and without arguments).

    2. The general quality of the code. I feel it can always be improved and made more Rusty.

    3. The organization of the files and the containing code, and the documentation.

    4. The external tests that I've included. Any additions/modifications necessary?


    I reiterate my invitation for general criticism as well.










    share|improve this question
























      up vote
      3
      down vote

      favorite









      up vote
      3
      down vote

      favorite











      Introduction



      I decided to get my feet wet in Rust by going ahead an implementing a full crate with the tests, documentation, and all other accompanying stuff. This is a toy implementation of a library containing a function that checks whether a given u64 is prime or not.



      What I've also done is implement a main.rs in addition to the lib.rs, that produces an executable when the cargo run or cargo build command is issued. So far the toolchain hasn't complained yet. It seems to be working fine, but I seek adivce on the practicality of it.



      The organization



      Here is the full structure (excluding the target folder):



      prime
      +- src
      | +- lib.rs
      | +- main.rs
      | +- prime.rs
      +- tests
      | +- extern_test.rs
      +- Cargo.lock
      +- Cargo.toml


      The files



      lib.rs



      pub mod prime;


      main.rs



      pub mod prime;

      use std::env;
      use std::io::stdin;

      fn take_input() {
      println!("Prime cheker utility.n=====================n");
      loop {
      process_single_line();
      if user_wants_to_exit() {
      break;
      }
      }
      }

      fn process_single_line() {
      let mut num_str: String = String::new();

      println!("Enter the number to check : ");

      stdin().read_line(&mut num_str).unwrap();

      process_string(num_str.trim());
      }

      fn user_wants_to_exit() -> bool {
      let mut usr_str = String::new();

      println!("Do you want to exit? (y/n) : ");
      stdin()
      .read_line(&mut usr_str)
      .expect("Error while reading input.");

      let trimmed = usr_str.trim();

      trimmed == "y" || trimmed == "Y" || trimmed.to_lowercase() == "yes"
      }

      fn process_string(num_str: &str) {
      let num = num_str.parse::<u64>().expect(INVALID_NUMBER);

      println!(
      "The integer {} is{} a prime.",
      num,
      match prime::is_prime(num) {
      true => "",
      false => " not",
      }
      );
      }

      const HELP_TEXT: &str = "USAGE:nn1. primen2. prime [unsigned integer]n";
      const INVALID_NUMBER: &str = "Please enter a valid unsigned integer.";

      fn main() {
      let args: Vec<String> = env::args().collect();
      match args.len() {
      1 => take_input(),
      2 => process_string(args[1].trim()),
      _ => {
      println!("{}", HELP_TEXT);
      }
      }
      }


      prime.rs



      /// This function takes a 64-bit unsigned integer and checks if it is a prime.
      ///
      /// If the number is prime, `true` is returned, and vice-versa.
      ///
      /// #Example
      ///
      /// ```rust
      /// use prime_util::*;
      ///
      /// let result = prime::is_prime(31);
      /// assert_eq!(result, true);
      /// ```
      pub fn is_prime(num: u64) -> bool {
      if num < 2 {
      return false;
      }
      if num == 2 || num == 3 {
      return true;
      }
      // Even numbers and multiples of 3 are eliminated
      if num % 2 == 0 || num % 3 == 0 {
      return false;
      }

      // Optimized divisor approach
      // First we calculate the maximum limit of iteration
      let limit = (num as f64).sqrt() as u64;
      // We start the iteration from 5 (2 and 3 have been already tested)
      let mut divisor = 5;
      // The step alternates between 2 and 4 to keep the divisor of the form
      // 6k +/- 1, where k is an integer
      let mut step = 2;
      while divisor <= limit {
      if num % divisor == 0 {
      return false;
      }
      divisor += step;
      step = if step == 2 { 4 } else { 2 }
      }
      true
      }


      extern_test.rs



      extern crate prime_util;

      #[cfg(test)]
      mod integration_test {
      use prime_util::prime;
      #[test]
      fn small_number_checks() {
      assert_eq!(prime::is_prime(11), true);
      assert_eq!(prime::is_prime(12), false);
      assert_eq!(prime::is_prime(13), true);
      }

      #[test]
      fn large_number_checks() {
      assert_eq!(prime::is_prime(179434027), true);
      assert_eq!(prime::is_prime(179434029), false);
      assert_eq!(prime::is_prime(179434031), false);
      assert_eq!(prime::is_prime(179434033), true);
      }

      #[test]
      fn first_10_numbers_tested() {
      assert_eq!(prime::is_prime(0), false);
      assert_eq!(prime::is_prime(1), false);
      assert_eq!(prime::is_prime(2), true);
      assert_eq!(prime::is_prime(3), true);
      assert_eq!(prime::is_prime(4), false);
      assert_eq!(prime::is_prime(5), true);
      assert_eq!(prime::is_prime(6), false);
      assert_eq!(prime::is_prime(7), true);
      assert_eq!(prime::is_prime(8), false);
      assert_eq!(prime::is_prime(9), false);
      assert_eq!(prime::is_prime(10), false);
      }
      }


      Others



      Cargo.toml is the default one. Nothing has been changed.



      Topics of interest



      I would like to point out some specific areas that I would like to hear advice on (although I always welcome comments on any aspect of the project):




      1. The fact that I have both main.rs and lib.rs. Cargo couldn't care less apparently. Because it executes all tests (even the documentation test) and also executes as a command-line program when cargo run is called (both with and without arguments).

      2. The general quality of the code. I feel it can always be improved and made more Rusty.

      3. The organization of the files and the containing code, and the documentation.

      4. The external tests that I've included. Any additions/modifications necessary?


      I reiterate my invitation for general criticism as well.










      share|improve this question













      Introduction



      I decided to get my feet wet in Rust by going ahead an implementing a full crate with the tests, documentation, and all other accompanying stuff. This is a toy implementation of a library containing a function that checks whether a given u64 is prime or not.



      What I've also done is implement a main.rs in addition to the lib.rs, that produces an executable when the cargo run or cargo build command is issued. So far the toolchain hasn't complained yet. It seems to be working fine, but I seek adivce on the practicality of it.



      The organization



      Here is the full structure (excluding the target folder):



      prime
      +- src
      | +- lib.rs
      | +- main.rs
      | +- prime.rs
      +- tests
      | +- extern_test.rs
      +- Cargo.lock
      +- Cargo.toml


      The files



      lib.rs



      pub mod prime;


      main.rs



      pub mod prime;

      use std::env;
      use std::io::stdin;

      fn take_input() {
      println!("Prime cheker utility.n=====================n");
      loop {
      process_single_line();
      if user_wants_to_exit() {
      break;
      }
      }
      }

      fn process_single_line() {
      let mut num_str: String = String::new();

      println!("Enter the number to check : ");

      stdin().read_line(&mut num_str).unwrap();

      process_string(num_str.trim());
      }

      fn user_wants_to_exit() -> bool {
      let mut usr_str = String::new();

      println!("Do you want to exit? (y/n) : ");
      stdin()
      .read_line(&mut usr_str)
      .expect("Error while reading input.");

      let trimmed = usr_str.trim();

      trimmed == "y" || trimmed == "Y" || trimmed.to_lowercase() == "yes"
      }

      fn process_string(num_str: &str) {
      let num = num_str.parse::<u64>().expect(INVALID_NUMBER);

      println!(
      "The integer {} is{} a prime.",
      num,
      match prime::is_prime(num) {
      true => "",
      false => " not",
      }
      );
      }

      const HELP_TEXT: &str = "USAGE:nn1. primen2. prime [unsigned integer]n";
      const INVALID_NUMBER: &str = "Please enter a valid unsigned integer.";

      fn main() {
      let args: Vec<String> = env::args().collect();
      match args.len() {
      1 => take_input(),
      2 => process_string(args[1].trim()),
      _ => {
      println!("{}", HELP_TEXT);
      }
      }
      }


      prime.rs



      /// This function takes a 64-bit unsigned integer and checks if it is a prime.
      ///
      /// If the number is prime, `true` is returned, and vice-versa.
      ///
      /// #Example
      ///
      /// ```rust
      /// use prime_util::*;
      ///
      /// let result = prime::is_prime(31);
      /// assert_eq!(result, true);
      /// ```
      pub fn is_prime(num: u64) -> bool {
      if num < 2 {
      return false;
      }
      if num == 2 || num == 3 {
      return true;
      }
      // Even numbers and multiples of 3 are eliminated
      if num % 2 == 0 || num % 3 == 0 {
      return false;
      }

      // Optimized divisor approach
      // First we calculate the maximum limit of iteration
      let limit = (num as f64).sqrt() as u64;
      // We start the iteration from 5 (2 and 3 have been already tested)
      let mut divisor = 5;
      // The step alternates between 2 and 4 to keep the divisor of the form
      // 6k +/- 1, where k is an integer
      let mut step = 2;
      while divisor <= limit {
      if num % divisor == 0 {
      return false;
      }
      divisor += step;
      step = if step == 2 { 4 } else { 2 }
      }
      true
      }


      extern_test.rs



      extern crate prime_util;

      #[cfg(test)]
      mod integration_test {
      use prime_util::prime;
      #[test]
      fn small_number_checks() {
      assert_eq!(prime::is_prime(11), true);
      assert_eq!(prime::is_prime(12), false);
      assert_eq!(prime::is_prime(13), true);
      }

      #[test]
      fn large_number_checks() {
      assert_eq!(prime::is_prime(179434027), true);
      assert_eq!(prime::is_prime(179434029), false);
      assert_eq!(prime::is_prime(179434031), false);
      assert_eq!(prime::is_prime(179434033), true);
      }

      #[test]
      fn first_10_numbers_tested() {
      assert_eq!(prime::is_prime(0), false);
      assert_eq!(prime::is_prime(1), false);
      assert_eq!(prime::is_prime(2), true);
      assert_eq!(prime::is_prime(3), true);
      assert_eq!(prime::is_prime(4), false);
      assert_eq!(prime::is_prime(5), true);
      assert_eq!(prime::is_prime(6), false);
      assert_eq!(prime::is_prime(7), true);
      assert_eq!(prime::is_prime(8), false);
      assert_eq!(prime::is_prime(9), false);
      assert_eq!(prime::is_prime(10), false);
      }
      }


      Others



      Cargo.toml is the default one. Nothing has been changed.



      Topics of interest



      I would like to point out some specific areas that I would like to hear advice on (although I always welcome comments on any aspect of the project):




      1. The fact that I have both main.rs and lib.rs. Cargo couldn't care less apparently. Because it executes all tests (even the documentation test) and also executes as a command-line program when cargo run is called (both with and without arguments).

      2. The general quality of the code. I feel it can always be improved and made more Rusty.

      3. The organization of the files and the containing code, and the documentation.

      4. The external tests that I've included. Any additions/modifications necessary?


      I reiterate my invitation for general criticism as well.







      beginner primes rust






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked 2 days ago









      Astrobleme

      1,5561339




      1,5561339



























          active

          oldest

          votes











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














           

          draft saved


          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208488%2fa-rust-crate-with-both-main-rs-and-lib-rs-performing-primality-checking%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown






























          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















           

          draft saved


          draft discarded



















































           


          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208488%2fa-rust-crate-with-both-main-rs-and-lib-rs-performing-primality-checking%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Ellipse (mathématiques)

          Quarter-circle Tiles

          Mont Emei