natord-1.0.9/.gitignore000064400007650000024000000000221256657762500132350ustar0000000000000000target Cargo.lock natord-1.0.9/.travis.yml000064400007650000024000000006561256657762500133730ustar0000000000000000language: rust os: - linux - osx env: global: - LD_LIBRARY_PATH: /usr/local/lib - secure: XpYCYw/porQrkHIFlx5kVk/MUqoM7MtPvzQ/7EVFn/lChwr/GEFl8T1aGlt3HJJU3hKp1KeaDOuN8ew7TE3+ZS6KfTPv75fSTJuz10Z2mYH+7th4H8Yw8jAtK4ZkOmUeJGcpVQdPQUkyVCo1V6SUv+42M8HZBeJdR48RShT23Zw= script: - cargo build -v - cargo test -v - cargo doc after_script: - cd target && curl http://www.rust-ci.org/artifacts/put?t=$RUSTCI_TOKEN | sh natord-1.0.9/Cargo.toml000064400007650000024000000016731256660003000131630ustar0000000000000000# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g. crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "natord" version = "1.0.9" authors = ["Kang Seonghoon "] description = "Natural ordering for Rust" homepage = "https://github.com/lifthrasiir/rust-natord" documentation = "https://lifthrasiir.github.io/rust-natord/" readme = "README.md" keywords = ["sort", "order", "natural"] license = "MIT" repository = "https://github.com/lifthrasiir/rust-natord" [lib] name = "natord" path = "lib.rs" natord-1.0.9/Cargo.toml.orig000064400007650000024000000006601256660003000141150ustar0000000000000000[package] name = "natord" version = "1.0.9" authors = ["Kang Seonghoon "] description = "Natural ordering for Rust" homepage = "https://github.com/lifthrasiir/rust-natord" documentation = "https://lifthrasiir.github.io/rust-natord/" repository = "https://github.com/lifthrasiir/rust-natord" keywords = ["sort", "order", "natural"] readme = "README.md" license = "MIT" [lib] name = "natord" path = "lib.rs" natord-1.0.9/lib.rs000064400007650000024000000166341256660004000123530ustar0000000000000000// Natord: Natural ordering for Rust. // Copyright (c) 2014-2015, Kang Seonghoon. // See README.md and LICENSE.txt for details. /*! # Natord 1.0.9 Natural ordering for Rust. (also known as `rust-natord`) This allows for the comparison like this: ~~~~ {.rust} let mut files = vec!("rfc2086.txt", "rfc822.txt", "rfc1.txt"); files.sort_by(|&a, &b| natord::compare(a, b)); assert_eq!(files, ["rfc1.txt", "rfc822.txt", "rfc2086.txt"]); ~~~~ There are multiple natural ordering algorithms available. This version of natural ordering is inspired by [Martin Pool's `strnatcmp.c`](http://sourcefrog.net/projects/natsort/). */ #![crate_name = "natord"] #![crate_type = "lib"] use std::cmp::Ordering; use std::cmp::Ordering::{Less, Equal, Greater}; /// Compares two iterators of "characters" possibly containing "digits". /// The natural ordering can be customized with the following parameters: /// /// * `skip` returns true if the "character" does not affect the comparison, /// other than splitting two consecutive digits. /// * `cmp` compares two "characters", assuming that they are not "digits". /// * `to_digit` converts a "character" into a "digit" if possible. The digit of zero is special. pub fn compare_iter(left: L, right: R, mut skip: Skip, mut cmp: Cmp, mut to_digit: ToDigit) -> Ordering where L: Iterator, R: Iterator, Skip: for<'a> FnMut(&'a T) -> bool, Cmp: for<'a> FnMut(&'a T, &'a T) -> Ordering, ToDigit: for<'a> FnMut(&'a T) -> Option { let mut left = left.fuse(); let mut right = right.fuse(); let mut l; let mut r; let mut ll; let mut rr; macro_rules! read_left { () => ({ l = left.next(); ll = l.as_ref().and_then(|v| to_digit(v)); }) } macro_rules! read_right { () => ({ r = right.next(); rr = r.as_ref().and_then(|v| to_digit(v)); }) } macro_rules! return_unless_equal { ($ord:expr) => ( match $ord { Equal => {} lastcmp => return lastcmp, } ) } read_left!(); read_right!(); 'nondigits: loop { // skip preceding whitespaces while l.as_ref().map_or(false, |c| skip(c)) { read_left!(); } while r.as_ref().map_or(false, |c| skip(c)) { read_right!(); } match (l, r) { (Some(l_), Some(r_)) => match (ll, rr) { (Some(ll_), Some(rr_)) => { if ll_ == 0 || rr_ == 0 { // left-aligned matching. (`015` < `12`) return_unless_equal!(ll_.cmp(&rr_)); 'digits_left: loop { read_left!(); read_right!(); match (ll, rr) { (Some(ll_), Some(rr_)) => return_unless_equal!(ll_.cmp(&rr_)), (Some(_), None) => return Greater, (None, Some(_)) => return Less, (None, None) => break 'digits_left, } } } else { // right-aligned matching. (`15` < `123`) let mut lastcmp = ll_.cmp(&rr_); 'digits_right: loop { read_left!(); read_right!(); match (ll, rr) { (Some(ll_), Some(rr_)) => { // `lastcmp` is only used when there are the same number of // digits, so we only update it. if lastcmp == Equal { lastcmp = ll_.cmp(&rr_); } } (Some(_), None) => return Greater, (None, Some(_)) => return Less, (None, None) => break 'digits_right, } } return_unless_equal!(lastcmp); } continue 'nondigits; // do not read from the iterators again }, (_, _) => return_unless_equal!(cmp(&l_, &r_)), }, (Some(_), None) => return Greater, (None, Some(_)) => return Less, (None, None) => return Equal, } read_left!(); read_right!(); } } /// Compares two strings case-sensitively. /// It skips any Unicode whitespaces and handles a series of decimal digits. pub fn compare(left: &str, right: &str) -> Ordering { compare_iter(left.chars(), right.chars(), |&c| c.is_whitespace(), |&l, &r| l.cmp(&r), |&c| c.to_digit(10).map(|v| v as isize)) } /// Compares two strings case-insensitively. /// It skips any Unicode whitespaces and handles a series of decimal digits. pub fn compare_ignore_case(left: &str, right: &str) -> Ordering { // XXX what we really want is a case folding! // Unicode case folding can be done iteratively, but currently we don't have them in stdlib. let left_iter = left.chars().flat_map(|c| c.to_lowercase()); let right_iter = right.chars().flat_map(|c| c.to_lowercase()); compare_iter(left_iter, right_iter, |&c| c.is_whitespace(), |&l, &r| l.cmp(&r), |&c| c.to_digit(10).map(|v| v as isize)) } #[cfg(test)] mod tests { use super::compare; use std::cmp::Ordering; use std::cmp::Ordering::{Less, Equal, Greater}; fn check_total_order(strs: &[&str]) { fn ordering_to_op(ord: Ordering) -> &'static str { match ord { Greater => ">", Equal => "=", Less => "<", } } for (i, &x) in strs.iter().enumerate() { for (j, &y) in strs.iter().enumerate() { assert!(compare(x, y) == i.cmp(&j), "expected x {} y, returned x {} y (where x = `{}`, y = `{}`)", ordering_to_op(i.cmp(&j)), ordering_to_op(compare(x, y)), x, y); } } } #[test] fn test_numeric() { check_total_order(&["a", "a0", "a1", "a1a", "a1b", "a2", "a10", "a20"]); } #[test] fn test_multiple_parts() { check_total_order(&["x2-g8", "x2-y7", "x2-y8", "x8-y8"]); } #[test] fn test_leading_zeroes() { check_total_order(&["1.001", "1.002", "1.010", "1.02", "1.1", "1.3"]); } #[test] fn test_longer() { check_total_order(&[ "1-02", "1-2", "1-20", "10-20", "fred", "jane", "pic1", "pic2", "pic2a", "pic3", "pic4", "pic4 alpha", "pic 4 else", "pic4 last", "pic5", "pic5.07", "pic5.08", "pic5.13", "pic5.113", "pic 5 something", "pic 6", "pic 7", "pic100", "pic100a", "pic120", "pic121", "pic2000", "tom", "x2-g8", "x2-y7", "x2-y8", "x8-y8", ]); } } natord-1.0.9/LICENSE.txt000064400007650000024000000020731256657762500131000ustar0000000000000000The MIT License (MIT) Copyright (c) 2014, Kang Seonghoon. 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. natord-1.0.9/README.md000064400007650000024000000020121256660003300125010ustar0000000000000000[Natord][doc] 1.0.9 =================== [![Natord on Travis CI][travis-image]][travis] [travis-image]: https://travis-ci.org/lifthrasiir/rust-natord.png [travis]: https://travis-ci.org/lifthrasiir/rust-natord Natural ordering for Rust. (also known as `rust-natord`) This allows for the comparison like this: ~~~~ {.rust} let mut files = vec!("rfc2086.txt", "rfc822.txt", "rfc1.txt"); files.sort_by(|&a, &b| natord::compare(a, b)); assert_eq!(files, ["rfc1.txt", "rfc822.txt", "rfc2086.txt"]); ~~~~ It provides a `compare` and `compare_ignore_case` function for comparing strings, and also a `compare_iter` function for the customizable algorithm. There are multiple natural ordering algorithms available. This version of natural ordering is inspired by [Martin Pool's `strnatcmp.c`](http://sourcefrog.net/projects/natsort/). See the test cases in the source code to see what it can do and it cannot. Natord is written by Kang Seonghoon and licensed under the MIT/X11 license. [doc]: https://lifthrasiir.github.io/rust-natord/