Remove a number of deprecated crates

All of these crates have been deprecated for some time and properly live in the
rust-lang organization as cargo-based crates.

To update your code, depend on the rust-lang/foo repository via cargo.

[breaking-change]
This commit is contained in:
Alex Crichton 2014-10-14 21:57:50 -07:00
parent c121cbab35
commit fb169d5543
12 changed files with 4 additions and 8547 deletions

View File

@ -49,11 +49,11 @@
# automatically generated for all stage/host/target combinations.
################################################################################
TARGET_CRATES := libc std green native flate arena glob term semver \
uuid serialize sync getopts collections num test time rand \
url log regex graphviz core rbml rlibc alloc rustrt \
TARGET_CRATES := libc std green native flate arena term \
serialize sync getopts collections test time rand \
log regex graphviz core rbml rlibc alloc rustrt \
unicode
HOST_CRATES := syntax rustc rustdoc fourcc hexfloat regex_macros fmt_macros \
HOST_CRATES := syntax rustc rustdoc regex_macros fmt_macros \
rustc_llvm rustc_back
CRATES := $(TARGET_CRATES) $(HOST_CRATES)
TOOLS := compiletest rustdoc rustc
@ -83,18 +83,13 @@ DEPS_glob := std
DEPS_serialize := std log
DEPS_rbml := std log serialize
DEPS_term := std log
DEPS_semver := std
DEPS_uuid := std serialize
DEPS_sync := core alloc rustrt collections
DEPS_getopts := std
DEPS_collections := core alloc unicode
DEPS_fourcc := rustc syntax std
DEPS_hexfloat := rustc syntax std
DEPS_num := std
DEPS_test := std getopts serialize rbml term time regex native:rust_test_helpers
DEPS_time := std serialize
DEPS_rand := core
DEPS_url := std
DEPS_log := std regex
DEPS_regex := std
DEPS_regex_macros = rustc syntax std regex

View File

@ -1,163 +0,0 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/*!
Syntax extension to generate FourCCs.
Once loaded, fourcc!() is called with a single 4-character string,
and an optional ident that is either `big`, `little`, or `target`.
The ident represents endianness, and specifies in which direction
the characters should be read. If the ident is omitted, it is assumed
to be `big`, i.e. left-to-right order. It returns a u32.
# Examples
To load the extension and use it:
```rust,ignore
#[phase(plugin)]
extern crate fourcc;
fn main() {
let val = fourcc!("\xC0\xFF\xEE!");
assert_eq!(val, 0xC0FFEE21u32);
let little_val = fourcc!("foo ", little);
assert_eq!(little_val, 0x21EEFFC0u32);
}
```
# References
* [Wikipedia: FourCC](http://en.wikipedia.org/wiki/FourCC)
*/
#![crate_name = "fourcc"]
#![deprecated = "This is now a cargo package located at: \
https://github.com/rust-lang/fourcc"]
#![allow(deprecated)]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
#![feature(plugin_registrar)]
extern crate syntax;
extern crate rustc;
use syntax::ast;
use syntax::attr::contains;
use syntax::codemap::{Span, mk_sp};
use syntax::ext::base;
use syntax::ext::base::{ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
use rustc::plugin::Registry;
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_macro("fourcc", expand_syntax_ext);
}
pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-> Box<base::MacResult+'cx> {
let (expr, endian) = parse_tts(cx, tts);
let little = match endian {
None => false,
Some(Ident{ident, span}) => match token::get_ident(ident).get() {
"little" => true,
"big" => false,
"target" => target_endian_little(cx, sp),
_ => {
cx.span_err(span, "invalid endian directive in fourcc!");
target_endian_little(cx, sp)
}
}
};
let s = match expr.node {
// expression is a literal
ast::ExprLit(ref lit) => match lit.node {
// string literal
ast::LitStr(ref s, _) => {
if s.get().char_len() != 4 {
cx.span_err(expr.span, "string literal with len != 4 in fourcc!");
}
s
}
_ => {
cx.span_err(expr.span, "unsupported literal in fourcc!");
return base::DummyResult::expr(sp)
}
},
_ => {
cx.span_err(expr.span, "non-literal in fourcc!");
return base::DummyResult::expr(sp)
}
};
let mut val = 0u32;
for codepoint in s.get().chars().take(4) {
let byte = if codepoint as u32 > 0xFF {
cx.span_err(expr.span, "fourcc! literal character out of range 0-255");
0u8
} else {
codepoint as u8
};
val = if little {
(val >> 8) | ((byte as u32) << 24)
} else {
(val << 8) | (byte as u32)
};
}
let e = cx.expr_lit(sp, ast::LitInt(val as u64, ast::UnsignedIntLit(ast::TyU32)));
MacExpr::new(e)
}
struct Ident {
ident: ast::Ident,
span: Span
}
fn parse_tts(cx: &ExtCtxt,
tts: &[ast::TokenTree]) -> (P<ast::Expr>, Option<Ident>) {
let p = &mut cx.new_parser_from_tts(tts);
let ex = p.parse_expr();
let id = if p.token == token::EOF {
None
} else {
p.expect(&token::COMMA);
let lo = p.span.lo;
let ident = p.parse_ident();
let hi = p.last_span.hi;
Some(Ident{ident: ident, span: mk_sp(lo, hi)})
};
if p.token != token::EOF {
p.unexpected();
}
(ex, id)
}
fn target_endian_little(cx: &ExtCtxt, sp: Span) -> bool {
let meta = cx.meta_name_value(sp, InternedString::new("target_endian"),
ast::LitStr(InternedString::new("little"), ast::CookedStr));
contains(cx.cfg().as_slice(), &*meta)
}
// FIXME (10872): This is required to prevent an LLVM assert on Windows
#[test]
fn dummy_test() { }

View File

@ -1,893 +0,0 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/*!
* Support for matching file paths against Unix shell style patterns.
*
* The `glob` and `glob_with` functions, in concert with the `Paths`
* type, allow querying the filesystem for all files that match a particular
* pattern - just like the libc `glob` function (for an example see the `glob`
* documentation). The methods on the `Pattern` type provide functionality
* for checking if individual paths match a particular pattern - in a similar
* manner to the libc `fnmatch` function
*
* For consistency across platforms, and for Windows support, this module
* is implemented entirely in Rust rather than deferring to the libc
* `glob`/`fnmatch` functions.
*/
#![crate_name = "glob"]
#![deprecated = "This is now a cargo package located at: \
https://github.com/rust-lang/glob"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/",
html_playground_url = "http://play.rust-lang.org/")]
#![allow(deprecated)]
use std::cell::Cell;
use std::{cmp, os, path};
use std::io::fs::PathExtensions;
use std::io::fs;
use std::path::is_sep;
use std::string::String;
/**
* An iterator that yields Paths from the filesystem that match a particular
* pattern - see the `glob` function for more details.
*/
pub struct Paths {
dir_patterns: Vec<Pattern>,
require_dir: bool,
options: MatchOptions,
todo: Vec<(Path,uint)>,
}
///
/// Return an iterator that produces all the Paths that match the given pattern,
/// which may be absolute or relative to the current working directory.
///
/// This method uses the default match options and is equivalent to calling
/// `glob_with(pattern, MatchOptions::new())`. Use `glob_with` directly if you
/// want to use non-default match options.
///
/// # Example
///
/// Consider a directory `/media/pictures` containing only the files `kittens.jpg`,
/// `puppies.jpg` and `hamsters.gif`:
///
/// ```rust
/// # #![allow(deprecated)]
/// use glob::glob;
///
/// for path in glob("/media/pictures/*.jpg") {
/// println!("{}", path.display());
/// }
/// ```
///
/// The above code will print:
///
/// ```ignore
/// /media/pictures/kittens.jpg
/// /media/pictures/puppies.jpg
/// ```
///
pub fn glob(pattern: &str) -> Paths {
glob_with(pattern, MatchOptions::new())
}
/**
* Return an iterator that produces all the Paths that match the given pattern,
* which may be absolute or relative to the current working directory.
*
* This function accepts Unix shell style patterns as described by `Pattern::new(..)`.
* The options given are passed through unchanged to `Pattern::matches_with(..)` with
* the exception that `require_literal_separator` is always set to `true` regardless of the
* value passed to this function.
*
* Paths are yielded in alphabetical order, as absolute paths.
*/
pub fn glob_with(pattern: &str, options: MatchOptions) -> Paths {
#[cfg(windows)]
fn check_windows_verbatim(p: &Path) -> bool { path::windows::is_verbatim(p) }
#[cfg(not(windows))]
fn check_windows_verbatim(_: &Path) -> bool { false }
// calculate root this way to handle volume-relative Windows paths correctly
let mut root = os::getcwd();
let pat_root = Path::new(pattern).root_path();
if pat_root.is_some() {
if check_windows_verbatim(pat_root.as_ref().unwrap()) {
// FIXME: How do we want to handle verbatim paths? I'm inclined to return nothing,
// since we can't very well find all UNC shares with a 1-letter server name.
return Paths {
dir_patterns: Vec::new(),
require_dir: false,
options: options,
todo: Vec::new(),
};
}
root.push(pat_root.as_ref().unwrap());
}
let root_len = pat_root.map_or(0u, |p| p.as_vec().len());
let dir_patterns = pattern.slice_from(cmp::min(root_len, pattern.len()))
.split_terminator(is_sep)
.map(|s| Pattern::new(s))
.collect::<Vec<Pattern>>();
let require_dir = pattern.chars().next_back().map(is_sep) == Some(true);
let mut todo = Vec::new();
if dir_patterns.len() > 0 {
// Shouldn't happen, but we're using -1 as a special index.
assert!(dir_patterns.len() < -1 as uint);
fill_todo(&mut todo, dir_patterns.as_slice(), 0, &root, options);
}
Paths {
dir_patterns: dir_patterns,
require_dir: require_dir,
options: options,
todo: todo,
}
}
impl Iterator<Path> for Paths {
fn next(&mut self) -> Option<Path> {
loop {
if self.dir_patterns.is_empty() || self.todo.is_empty() {
return None;
}
let (path,idx) = self.todo.pop().unwrap();
// idx -1: was already checked by fill_todo, maybe path was '.' or
// '..' that we can't match here because of normalization.
if idx == -1 as uint {
if self.require_dir && !path.is_dir() { continue; }
return Some(path);
}
let ref pattern = self.dir_patterns[idx];
if pattern.matches_with(match path.filename_str() {
// this ugly match needs to go here to avoid a borrowck error
None => {
// FIXME (#9639): How do we handle non-utf8 filenames? Ignore them for now
// Ideally we'd still match them against a *
continue;
}
Some(x) => x
}, self.options) {
if idx == self.dir_patterns.len() - 1 {
// it is not possible for a pattern to match a directory *AND* its children
// so we don't need to check the children
if !self.require_dir || path.is_dir() {
return Some(path);
}
} else {
fill_todo(&mut self.todo, self.dir_patterns.as_slice(),
idx + 1, &path, self.options);
}
}
}
}
}
fn list_dir_sorted(path: &Path) -> Option<Vec<Path>> {
match fs::readdir(path) {
Ok(mut children) => {
children.sort_by(|p1, p2| p2.filename().cmp(&p1.filename()));
Some(children.into_iter().collect())
}
Err(..) => None
}
}
/**
* A compiled Unix shell style pattern.
*/
#[deriving(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Pattern {
tokens: Vec<PatternToken>,
}
#[deriving(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum PatternToken {
Char(char),
AnyChar,
AnySequence,
AnyWithin(Vec<CharSpecifier> ),
AnyExcept(Vec<CharSpecifier> )
}
#[deriving(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum CharSpecifier {
SingleChar(char),
CharRange(char, char)
}
#[deriving(PartialEq)]
enum MatchResult {
Match,
SubPatternDoesntMatch,
EntirePatternDoesntMatch
}
impl Pattern {
/**
* This function compiles Unix shell style patterns: `?` matches any single
* character, `*` matches any (possibly empty) sequence of characters and
* `[...]` matches any character inside the brackets, unless the first
* character is `!` in which case it matches any character except those
* between the `!` and the `]`. Character sequences can also specify ranges
* of characters, as ordered by Unicode, so e.g. `[0-9]` specifies any
* character between 0 and 9 inclusive.
*
* The metacharacters `?`, `*`, `[`, `]` can be matched by using brackets
* (e.g. `[?]`). When a `]` occurs immediately following `[` or `[!` then
* it is interpreted as being part of, rather then ending, the character
* set, so `]` and NOT `]` can be matched by `[]]` and `[!]]` respectively.
* The `-` character can be specified inside a character sequence pattern by
* placing it at the start or the end, e.g. `[abc-]`.
*
* When a `[` does not have a closing `]` before the end of the string then
* the `[` will be treated literally.
*/
pub fn new(pattern: &str) -> Pattern {
let chars = pattern.chars().collect::<Vec<_>>();
let mut tokens = Vec::new();
let mut i = 0;
while i < chars.len() {
match chars[i] {
'?' => {
tokens.push(AnyChar);
i += 1;
}
'*' => {
// *, **, ***, ****, ... are all equivalent
while i < chars.len() && chars[i] == '*' {
i += 1;
}
tokens.push(AnySequence);
}
'[' => {
if i <= chars.len() - 4 && chars[i + 1] == '!' {
match chars.slice_from(i + 3).position_elem(&']') {
None => (),
Some(j) => {
let chars = chars.slice(i + 2, i + 3 + j);
let cs = parse_char_specifiers(chars);
tokens.push(AnyExcept(cs));
i += j + 4;
continue;
}
}
}
else if i <= chars.len() - 3 && chars[i + 1] != '!' {
match chars.slice_from(i + 2).position_elem(&']') {
None => (),
Some(j) => {
let cs = parse_char_specifiers(chars.slice(i + 1, i + 2 + j));
tokens.push(AnyWithin(cs));
i += j + 3;
continue;
}
}
}
// if we get here then this is not a valid range pattern
tokens.push(Char('['));
i += 1;
}
c => {
tokens.push(Char(c));
i += 1;
}
}
}
Pattern { tokens: tokens }
}
/**
* Escape metacharacters within the given string by surrounding them in
* brackets. The resulting string will, when compiled into a `Pattern`,
* match the input string and nothing else.
*/
pub fn escape(s: &str) -> String {
let mut escaped = String::new();
for c in s.chars() {
match c {
// note that ! does not need escaping because it is only special inside brackets
'?' | '*' | '[' | ']' => {
escaped.push_char('[');
escaped.push_char(c);
escaped.push_char(']');
}
c => {
escaped.push_char(c);
}
}
}
escaped
}
/**
* Return if the given `str` matches this `Pattern` using the default
* match options (i.e. `MatchOptions::new()`).
*
* # Example
*
* ```rust
* #![allow(deprecated)]
* use glob::Pattern;
*
* assert!(Pattern::new("c?t").matches("cat"));
* assert!(Pattern::new("k[!e]tteh").matches("kitteh"));
* assert!(Pattern::new("d*g").matches("doog"));
* ```
*/
pub fn matches(&self, str: &str) -> bool {
self.matches_with(str, MatchOptions::new())
}
/**
* Return if the given `Path`, when converted to a `str`, matches this `Pattern`
* using the default match options (i.e. `MatchOptions::new()`).
*/
pub fn matches_path(&self, path: &Path) -> bool {
// FIXME (#9639): This needs to handle non-utf8 paths
path.as_str().map_or(false, |s| {
self.matches(s)
})
}
/**
* Return if the given `str` matches this `Pattern` using the specified match options.
*/
pub fn matches_with(&self, str: &str, options: MatchOptions) -> bool {
self.matches_from(None, str, 0, options) == Match
}
/**
* Return if the given `Path`, when converted to a `str`, matches this `Pattern`
* using the specified match options.
*/
pub fn matches_path_with(&self, path: &Path, options: MatchOptions) -> bool {
// FIXME (#9639): This needs to handle non-utf8 paths
path.as_str().map_or(false, |s| {
self.matches_with(s, options)
})
}
fn matches_from(&self,
prev_char: Option<char>,
mut file: &str,
i: uint,
options: MatchOptions) -> MatchResult {
let prev_char = Cell::new(prev_char);
let require_literal = |c| {
(options.require_literal_separator && is_sep(c)) ||
(options.require_literal_leading_dot && c == '.'
&& is_sep(prev_char.get().unwrap_or('/')))
};
for (ti, token) in self.tokens.slice_from(i).iter().enumerate() {
match *token {
AnySequence => {
loop {
match self.matches_from(prev_char.get(), file, i + ti + 1, options) {
SubPatternDoesntMatch => (), // keep trying
m => return m,
}
if file.is_empty() {
return EntirePatternDoesntMatch;
}
let (some_c, next) = file.slice_shift_char();
if require_literal(some_c.unwrap()) {
return SubPatternDoesntMatch;
}
prev_char.set(some_c);
file = next;
}
}
_ => {
if file.is_empty() {
return EntirePatternDoesntMatch;
}
let (some_c, next) = file.slice_shift_char();
let c = some_c.unwrap();
let matches = match *token {
AnyChar => {
!require_literal(c)
}
AnyWithin(ref specifiers) => {
!require_literal(c) &&
in_char_specifiers(specifiers.as_slice(),
c,
options)
}
AnyExcept(ref specifiers) => {
!require_literal(c) &&
!in_char_specifiers(specifiers.as_slice(),
c,
options)
}
Char(c2) => {
chars_eq(c, c2, options.case_sensitive)
}
AnySequence => {
unreachable!()
}
};
if !matches {
return SubPatternDoesntMatch;
}
prev_char.set(some_c);
file = next;
}
}
}
if file.is_empty() {
Match
} else {
SubPatternDoesntMatch
}
}
}
// Fills `todo` with paths under `path` to be matched by `patterns[idx]`,
// special-casing patterns to match `.` and `..`, and avoiding `readdir()`
// calls when there are no metacharacters in the pattern.
fn fill_todo(todo: &mut Vec<(Path, uint)>, patterns: &[Pattern], idx: uint, path: &Path,
options: MatchOptions) {
// convert a pattern that's just many Char(_) to a string
fn pattern_as_str(pattern: &Pattern) -> Option<String> {
let mut s = String::new();
for token in pattern.tokens.iter() {
match *token {
Char(c) => s.push_char(c),
_ => return None
}
}
return Some(s);
}
let add = |todo: &mut Vec<_>, next_path: Path| {
if idx + 1 == patterns.len() {
// We know it's good, so don't make the iterator match this path
// against the pattern again. In particular, it can't match
// . or .. globs since these never show up as path components.
todo.push((next_path, -1 as uint));
} else {
fill_todo(todo, patterns, idx + 1, &next_path, options);
}
};
let pattern = &patterns[idx];
match pattern_as_str(pattern) {
Some(s) => {
// This pattern component doesn't have any metacharacters, so we
// don't need to read the current directory to know where to
// continue. So instead of passing control back to the iterator,
// we can just check for that one entry and potentially recurse
// right away.
let special = "." == s.as_slice() || ".." == s.as_slice();
let next_path = path.join(s.as_slice());
if (special && path.is_dir()) || (!special && next_path.exists()) {
add(todo, next_path);
}
},
None => {
match list_dir_sorted(path) {
Some(entries) => {
todo.extend(entries.into_iter().map(|x|(x, idx)));
// Matching the special directory entries . and .. that refer to
// the current and parent directory respectively requires that
// the pattern has a leading dot, even if the `MatchOptions` field
// `require_literal_leading_dot` is not set.
if pattern.tokens.len() > 0 && pattern.tokens[0] == Char('.') {
for &special in [".", ".."].iter() {
if pattern.matches_with(special, options) {
add(todo, path.join(special));
}
}
}
}
None => {}
}
}
}
}
fn parse_char_specifiers(s: &[char]) -> Vec<CharSpecifier> {
let mut cs = Vec::new();
let mut i = 0;
while i < s.len() {
if i + 3 <= s.len() && s[i + 1] == '-' {
cs.push(CharRange(s[i], s[i + 2]));
i += 3;
} else {
cs.push(SingleChar(s[i]));
i += 1;
}
}
cs
}
fn in_char_specifiers(specifiers: &[CharSpecifier], c: char, options: MatchOptions) -> bool {
for &specifier in specifiers.iter() {
match specifier {
SingleChar(sc) => {
if chars_eq(c, sc, options.case_sensitive) {
return true;
}
}
CharRange(start, end) => {
// FIXME: work with non-ascii chars properly (issue #1347)
if !options.case_sensitive && c.is_ascii() && start.is_ascii() && end.is_ascii() {
let start = start.to_ascii().to_lowercase();
let end = end.to_ascii().to_lowercase();
let start_up = start.to_uppercase();
let end_up = end.to_uppercase();
// only allow case insensitive matching when
// both start and end are within a-z or A-Z
if start != start_up && end != end_up {
let start = start.to_char();
let end = end.to_char();
let c = c.to_ascii().to_lowercase().to_char();
if c >= start && c <= end {
return true;
}
}
}
if c >= start && c <= end {
return true;
}
}
}
}
false
}
/// A helper function to determine if two chars are (possibly case-insensitively) equal.
fn chars_eq(a: char, b: char, case_sensitive: bool) -> bool {
if cfg!(windows) && path::windows::is_sep(a) && path::windows::is_sep(b) {
true
} else if !case_sensitive && a.is_ascii() && b.is_ascii() {
// FIXME: work with non-ascii chars properly (issue #1347)
a.to_ascii().eq_ignore_case(b.to_ascii())
} else {
a == b
}
}
/**
* Configuration options to modify the behaviour of `Pattern::matches_with(..)`
*/
#[deriving(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct MatchOptions {
/**
* Whether or not patterns should be matched in a case-sensitive manner. This
* currently only considers upper/lower case relationships between ASCII characters,
* but in future this might be extended to work with Unicode.
*/
pub case_sensitive: bool,
/**
* If this is true then path-component separator characters (e.g. `/` on Posix)
* must be matched by a literal `/`, rather than by `*` or `?` or `[...]`
*/
pub require_literal_separator: bool,
/**
* If this is true then paths that contain components that start with a `.` will
* not match unless the `.` appears literally in the pattern: `*`, `?` or `[...]`
* will not match. This is useful because such files are conventionally considered
* hidden on Unix systems and it might be desirable to skip them when listing files.
*/
pub require_literal_leading_dot: bool
}
impl MatchOptions {
/**
* Constructs a new `MatchOptions` with default field values. This is used
* when calling functions that do not take an explicit `MatchOptions` parameter.
*
* This function always returns this value:
*
* ```rust,ignore
* MatchOptions {
* case_sensitive: true,
* require_literal_separator: false.
* require_literal_leading_dot: false
* }
* ```
*/
pub fn new() -> MatchOptions {
MatchOptions {
case_sensitive: true,
require_literal_separator: false,
require_literal_leading_dot: false
}
}
}
#[cfg(test)]
mod test {
use std::os;
use super::{glob, Pattern, MatchOptions};
#[test]
fn test_absolute_pattern() {
// assume that the filesystem is not empty!
assert!(glob("/*").next().is_some());
assert!(glob("//").next().is_some());
// check windows absolute paths with host/device components
let root_with_device = os::getcwd().root_path().unwrap().join("*");
// FIXME (#9639): This needs to handle non-utf8 paths
assert!(glob(root_with_device.as_str().unwrap()).next().is_some());
}
#[test]
fn test_wildcard_optimizations() {
assert!(Pattern::new("a*b").matches("a___b"));
assert!(Pattern::new("a**b").matches("a___b"));
assert!(Pattern::new("a***b").matches("a___b"));
assert!(Pattern::new("a*b*c").matches("abc"));
assert!(!Pattern::new("a*b*c").matches("abcd"));
assert!(Pattern::new("a*b*c").matches("a_b_c"));
assert!(Pattern::new("a*b*c").matches("a___b___c"));
assert!(Pattern::new("abc*abc*abc").matches("abcabcabcabcabcabcabc"));
assert!(!Pattern::new("abc*abc*abc").matches("abcabcabcabcabcabcabca"));
assert!(Pattern::new("a*a*a*a*a*a*a*a*a").matches("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
assert!(Pattern::new("a*b[xyz]c*d").matches("abxcdbxcddd"));
}
#[test]
#[cfg_attr(windows, ignore)] // FIXME (#9406)
fn test_lots_of_files() {
// this is a good test because it touches lots of differently named files
glob("/*/*/*/*").skip(10000).next();
}
#[test]
fn test_range_pattern() {
let pat = Pattern::new("a[0-9]b");
for i in range(0u, 10) {
assert!(pat.matches(format!("a{}b", i).as_slice()));
}
assert!(!pat.matches("a_b"));
let pat = Pattern::new("a[!0-9]b");
for i in range(0u, 10) {
assert!(!pat.matches(format!("a{}b", i).as_slice()));
}
assert!(pat.matches("a_b"));
let pats = ["[a-z123]", "[1a-z23]", "[123a-z]"];
for &p in pats.iter() {
let pat = Pattern::new(p);
for c in "abcdefghijklmnopqrstuvwxyz".chars() {
assert!(pat.matches(c.to_string().as_slice()));
}
for c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ".chars() {
let options = MatchOptions {case_sensitive: false, .. MatchOptions::new()};
assert!(pat.matches_with(c.to_string().as_slice(), options));
}
assert!(pat.matches("1"));
assert!(pat.matches("2"));
assert!(pat.matches("3"));
}
let pats = ["[abc-]", "[-abc]", "[a-c-]"];
for &p in pats.iter() {
let pat = Pattern::new(p);
assert!(pat.matches("a"));
assert!(pat.matches("b"));
assert!(pat.matches("c"));
assert!(pat.matches("-"));
assert!(!pat.matches("d"));
}
let pat = Pattern::new("[2-1]");
assert!(!pat.matches("1"));
assert!(!pat.matches("2"));
assert!(Pattern::new("[-]").matches("-"));
assert!(!Pattern::new("[!-]").matches("-"));
}
#[test]
fn test_unclosed_bracket() {
// unclosed `[` should be treated literally
assert!(Pattern::new("abc[def").matches("abc[def"));
assert!(Pattern::new("abc[!def").matches("abc[!def"));
assert!(Pattern::new("abc[").matches("abc["));
assert!(Pattern::new("abc[!").matches("abc[!"));
assert!(Pattern::new("abc[d").matches("abc[d"));
assert!(Pattern::new("abc[!d").matches("abc[!d"));
assert!(Pattern::new("abc[]").matches("abc[]"));
assert!(Pattern::new("abc[!]").matches("abc[!]"));
}
#[test]
fn test_pattern_matches() {
let txt_pat = Pattern::new("*hello.txt");
assert!(txt_pat.matches("hello.txt"));
assert!(txt_pat.matches("gareth_says_hello.txt"));
assert!(txt_pat.matches("some/path/to/hello.txt"));
assert!(txt_pat.matches("some\\path\\to\\hello.txt"));
assert!(txt_pat.matches("/an/absolute/path/to/hello.txt"));
assert!(!txt_pat.matches("hello.txt-and-then-some"));
assert!(!txt_pat.matches("goodbye.txt"));
let dir_pat = Pattern::new("*some/path/to/hello.txt");
assert!(dir_pat.matches("some/path/to/hello.txt"));
assert!(dir_pat.matches("a/bigger/some/path/to/hello.txt"));
assert!(!dir_pat.matches("some/path/to/hello.txt-and-then-some"));
assert!(!dir_pat.matches("some/other/path/to/hello.txt"));
}
#[test]
fn test_pattern_escape() {
let s = "_[_]_?_*_!_";
assert_eq!(Pattern::escape(s), "_[[]_[]]_[?]_[*]_!_".to_string());
assert!(Pattern::new(Pattern::escape(s).as_slice()).matches(s));
}
#[test]
fn test_pattern_matches_case_insensitive() {
let pat = Pattern::new("aBcDeFg");
let options = MatchOptions {
case_sensitive: false,
require_literal_separator: false,
require_literal_leading_dot: false
};
assert!(pat.matches_with("aBcDeFg", options));
assert!(pat.matches_with("abcdefg", options));
assert!(pat.matches_with("ABCDEFG", options));
assert!(pat.matches_with("AbCdEfG", options));
}
#[test]
fn test_pattern_matches_case_insensitive_range() {
let pat_within = Pattern::new("[a]");
let pat_except = Pattern::new("[!a]");
let options_case_insensitive = MatchOptions {
case_sensitive: false,
require_literal_separator: false,
require_literal_leading_dot: false
};
let options_case_sensitive = MatchOptions {
case_sensitive: true,
require_literal_separator: false,
require_literal_leading_dot: false
};
assert!(pat_within.matches_with("a", options_case_insensitive));
assert!(pat_within.matches_with("A", options_case_insensitive));
assert!(!pat_within.matches_with("A", options_case_sensitive));
assert!(!pat_except.matches_with("a", options_case_insensitive));
assert!(!pat_except.matches_with("A", options_case_insensitive));
assert!(pat_except.matches_with("A", options_case_sensitive));
}
#[test]
fn test_pattern_matches_require_literal_separator() {
let options_require_literal = MatchOptions {
case_sensitive: true,
require_literal_separator: true,
require_literal_leading_dot: false
};
let options_not_require_literal = MatchOptions {
case_sensitive: true,
require_literal_separator: false,
require_literal_leading_dot: false
};
assert!(Pattern::new("abc/def").matches_with("abc/def", options_require_literal));
assert!(!Pattern::new("abc?def").matches_with("abc/def", options_require_literal));
assert!(!Pattern::new("abc*def").matches_with("abc/def", options_require_literal));
assert!(!Pattern::new("abc[/]def").matches_with("abc/def", options_require_literal));
assert!(Pattern::new("abc/def").matches_with("abc/def", options_not_require_literal));
assert!(Pattern::new("abc?def").matches_with("abc/def", options_not_require_literal));
assert!(Pattern::new("abc*def").matches_with("abc/def", options_not_require_literal));
assert!(Pattern::new("abc[/]def").matches_with("abc/def", options_not_require_literal));
}
#[test]
fn test_pattern_matches_require_literal_leading_dot() {
let options_require_literal_leading_dot = MatchOptions {
case_sensitive: true,
require_literal_separator: false,
require_literal_leading_dot: true
};
let options_not_require_literal_leading_dot = MatchOptions {
case_sensitive: true,
require_literal_separator: false,
require_literal_leading_dot: false
};
let f = |options| Pattern::new("*.txt").matches_with(".hello.txt", options);
assert!(f(options_not_require_literal_leading_dot));
assert!(!f(options_require_literal_leading_dot));
let f = |options| Pattern::new(".*.*").matches_with(".hello.txt", options);
assert!(f(options_not_require_literal_leading_dot));
assert!(f(options_require_literal_leading_dot));
let f = |options| Pattern::new("aaa/bbb/*").matches_with("aaa/bbb/.ccc", options);
assert!(f(options_not_require_literal_leading_dot));
assert!(!f(options_require_literal_leading_dot));
let f = |options| Pattern::new("aaa/bbb/*").matches_with("aaa/bbb/c.c.c.", options);
assert!(f(options_not_require_literal_leading_dot));
assert!(f(options_require_literal_leading_dot));
let f = |options| Pattern::new("aaa/bbb/.*").matches_with("aaa/bbb/.ccc", options);
assert!(f(options_not_require_literal_leading_dot));
assert!(f(options_require_literal_leading_dot));
let f = |options| Pattern::new("aaa/?bbb").matches_with("aaa/.bbb", options);
assert!(f(options_not_require_literal_leading_dot));
assert!(!f(options_require_literal_leading_dot));
let f = |options| Pattern::new("aaa/[.]bbb").matches_with("aaa/.bbb", options);
assert!(f(options_not_require_literal_leading_dot));
assert!(!f(options_require_literal_leading_dot));
}
#[test]
fn test_matches_path() {
// on windows, (Path::new("a/b").as_str().unwrap() == "a\\b"), so this
// tests that / and \ are considered equivalent on windows
assert!(Pattern::new("a/b").matches_path(&Path::new("a/b")));
}
}

View File

@ -1,189 +0,0 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/*!
Syntax extension to create floating point literals from hexadecimal strings
Once loaded, hexfloat!() is called with a string containing the hexadecimal
floating-point literal, and an optional type (f32 or f64).
If the type is omitted, the literal is treated the same as a normal unsuffixed
literal.
# Examples
To load the extension and use it:
```rust,ignore
#[phase(plugin)]
extern crate hexfloat;
fn main() {
let val = hexfloat!("0x1.ffffb4", f32);
}
```
# References
* [ExploringBinary: hexadecimal floating point constants]
(http://www.exploringbinary.com/hexadecimal-floating-point-constants/)
*/
#![crate_name = "hexfloat"]
#![deprecated = "This is now a cargo package located at: \
https://github.com/rust-lang/hexfloat"]
#![allow(deprecated)]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
#![feature(plugin_registrar)]
extern crate syntax;
extern crate rustc;
use syntax::ast;
use syntax::codemap::{Span, mk_sp};
use syntax::ext::base;
use syntax::ext::base::{ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use syntax::ptr::P;
use rustc::plugin::Registry;
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_macro("hexfloat", expand_syntax_ext);
}
//Check if the literal is valid (as LLVM expects),
//and return a descriptive error if not.
fn hex_float_lit_err(s: &str) -> Option<(uint, String)> {
let mut chars = s.chars().peekable();
let mut i = 0;
if chars.peek() == Some(&'-') { chars.next(); i+= 1 }
if chars.next() != Some('0') {
return Some((i, "Expected '0'".to_string()));
} i+=1;
if chars.next() != Some('x') {
return Some((i, "Expected 'x'".to_string()));
} i+=1;
let mut d_len = 0i;
for _ in chars.take_while(|c| c.is_digit_radix(16)) { chars.next(); i+=1; d_len += 1;}
if chars.next() != Some('.') {
return Some((i, "Expected '.'".to_string()));
} i+=1;
let mut f_len = 0i;
for _ in chars.take_while(|c| c.is_digit_radix(16)) { chars.next(); i+=1; f_len += 1;}
if d_len == 0 && f_len == 0 {
return Some((i, "Expected digits before or after decimal \
point".to_string()));
}
if chars.next() != Some('p') {
return Some((i, "Expected 'p'".to_string()));
} i+=1;
if chars.peek() == Some(&'-') { chars.next(); i+= 1 }
let mut e_len = 0i;
for _ in chars.take_while(|c| c.is_digit()) { chars.next(); i+=1; e_len += 1}
if e_len == 0 {
return Some((i, "Expected exponent digits".to_string()));
}
match chars.next() {
None => None,
Some(_) => Some((i, "Expected end of string".to_string()))
}
}
pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-> Box<base::MacResult+'static> {
let (expr, ty_lit) = parse_tts(cx, tts);
let ty = match ty_lit {
None => None,
Some(Ident{ident, span}) => match token::get_ident(ident).get() {
"f32" => Some(ast::TyF32),
"f64" => Some(ast::TyF64),
_ => {
cx.span_err(span, "invalid floating point type in hexfloat!");
None
}
}
};
let s = match expr.node {
// expression is a literal
ast::ExprLit(ref lit) => match lit.node {
// string literal
ast::LitStr(ref s, _) => {
s.clone()
}
_ => {
cx.span_err(expr.span, "unsupported literal in hexfloat!");
return base::DummyResult::expr(sp);
}
},
_ => {
cx.span_err(expr.span, "non-literal in hexfloat!");
return base::DummyResult::expr(sp);
}
};
{
let err = hex_float_lit_err(s.get());
match err {
Some((err_pos, err_str)) => {
let pos = expr.span.lo + syntax::codemap::Pos::from_uint(err_pos + 1);
let span = syntax::codemap::mk_sp(pos,pos);
cx.span_err(span,
format!("invalid hex float literal in hexfloat!: \
{}",
err_str).as_slice());
return base::DummyResult::expr(sp);
}
_ => ()
}
}
let lit = match ty {
None => ast::LitFloatUnsuffixed(s),
Some (ty) => ast::LitFloat(s, ty)
};
MacExpr::new(cx.expr_lit(sp, lit))
}
struct Ident {
ident: ast::Ident,
span: Span
}
fn parse_tts(cx: &ExtCtxt,
tts: &[ast::TokenTree]) -> (P<ast::Expr>, Option<Ident>) {
let p = &mut cx.new_parser_from_tts(tts);
let ex = p.parse_expr();
let id = if p.token == token::EOF {
None
} else {
p.expect(&token::COMMA);
let lo = p.span.lo;
let ident = p.parse_ident();
let hi = p.last_span.hi;
Some(Ident{ident: ident, span: mk_sp(lo, hi)})
};
if p.token != token::EOF {
p.unexpected();
}
(ex, id)
}
// FIXME (10872): This is required to prevent an LLVM assert on Windows
#[test]
fn dummy_test() { }

File diff suppressed because it is too large Load Diff

View File

@ -1,379 +0,0 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Complex numbers.
use std::fmt;
use std::num::{Zero, One, ToStrRadix};
// FIXME #1284: handle complex NaN & infinity etc. This
// probably doesn't map to C's _Complex correctly.
/// A complex number in Cartesian form.
#[deriving(PartialEq, Clone, Hash)]
pub struct Complex<T> {
/// Real portion of the complex number
pub re: T,
/// Imaginary portion of the complex number
pub im: T
}
pub type Complex32 = Complex<f32>;
pub type Complex64 = Complex<f64>;
impl<T: Clone + Num> Complex<T> {
/// Create a new Complex
#[inline]
pub fn new(re: T, im: T) -> Complex<T> {
Complex { re: re, im: im }
}
/// Returns the square of the norm (since `T` doesn't necessarily
/// have a sqrt function), i.e. `re^2 + im^2`.
#[inline]
pub fn norm_sqr(&self) -> T {
self.re * self.re + self.im * self.im
}
/// Returns the complex conjugate. i.e. `re - i im`
#[inline]
pub fn conj(&self) -> Complex<T> {
Complex::new(self.re.clone(), -self.im)
}
/// Multiplies `self` by the scalar `t`.
#[inline]
pub fn scale(&self, t: T) -> Complex<T> {
Complex::new(self.re * t, self.im * t)
}
/// Divides `self` by the scalar `t`.
#[inline]
pub fn unscale(&self, t: T) -> Complex<T> {
Complex::new(self.re / t, self.im / t)
}
/// Returns `1/self`
#[inline]
pub fn inv(&self) -> Complex<T> {
let norm_sqr = self.norm_sqr();
Complex::new(self.re / norm_sqr,
-self.im / norm_sqr)
}
}
impl<T: Clone + FloatMath> Complex<T> {
/// Calculate |self|
#[inline]
pub fn norm(&self) -> T {
self.re.hypot(self.im)
}
}
impl<T: Clone + FloatMath> Complex<T> {
/// Calculate the principal Arg of self.
#[inline]
pub fn arg(&self) -> T {
self.im.atan2(self.re)
}
/// Convert to polar form (r, theta), such that `self = r * exp(i
/// * theta)`
#[inline]
pub fn to_polar(&self) -> (T, T) {
(self.norm(), self.arg())
}
/// Convert a polar representation into a complex number.
#[inline]
pub fn from_polar(r: &T, theta: &T) -> Complex<T> {
Complex::new(*r * theta.cos(), *r * theta.sin())
}
}
/* arithmetic */
// (a + i b) + (c + i d) == (a + c) + i (b + d)
impl<T: Clone + Num> Add<Complex<T>, Complex<T>> for Complex<T> {
#[inline]
fn add(&self, other: &Complex<T>) -> Complex<T> {
Complex::new(self.re + other.re, self.im + other.im)
}
}
// (a + i b) - (c + i d) == (a - c) + i (b - d)
impl<T: Clone + Num> Sub<Complex<T>, Complex<T>> for Complex<T> {
#[inline]
fn sub(&self, other: &Complex<T>) -> Complex<T> {
Complex::new(self.re - other.re, self.im - other.im)
}
}
// (a + i b) * (c + i d) == (a*c - b*d) + i (a*d + b*c)
impl<T: Clone + Num> Mul<Complex<T>, Complex<T>> for Complex<T> {
#[inline]
fn mul(&self, other: &Complex<T>) -> Complex<T> {
Complex::new(self.re*other.re - self.im*other.im,
self.re*other.im + self.im*other.re)
}
}
// (a + i b) / (c + i d) == [(a + i b) * (c - i d)] / (c*c + d*d)
// == [(a*c + b*d) / (c*c + d*d)] + i [(b*c - a*d) / (c*c + d*d)]
impl<T: Clone + Num> Div<Complex<T>, Complex<T>> for Complex<T> {
#[inline]
fn div(&self, other: &Complex<T>) -> Complex<T> {
let norm_sqr = other.norm_sqr();
Complex::new((self.re*other.re + self.im*other.im) / norm_sqr,
(self.im*other.re - self.re*other.im) / norm_sqr)
}
}
impl<T: Clone + Num> Neg<Complex<T>> for Complex<T> {
#[inline]
fn neg(&self) -> Complex<T> {
Complex::new(-self.re, -self.im)
}
}
/* constants */
impl<T: Clone + Num> Zero for Complex<T> {
#[inline]
fn zero() -> Complex<T> {
Complex::new(Zero::zero(), Zero::zero())
}
#[inline]
fn is_zero(&self) -> bool {
self.re.is_zero() && self.im.is_zero()
}
}
impl<T: Clone + Num> One for Complex<T> {
#[inline]
fn one() -> Complex<T> {
Complex::new(One::one(), Zero::zero())
}
}
/* string conversions */
impl<T: fmt::Show + Num + PartialOrd> fmt::Show for Complex<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.im < Zero::zero() {
write!(f, "{}-{}i", self.re, -self.im)
} else {
write!(f, "{}+{}i", self.re, self.im)
}
}
}
impl<T: ToStrRadix + Num + PartialOrd> ToStrRadix for Complex<T> {
fn to_str_radix(&self, radix: uint) -> String {
if self.im < Zero::zero() {
format!("{}-{}i",
self.re.to_str_radix(radix),
(-self.im).to_str_radix(radix))
} else {
format!("{}+{}i",
self.re.to_str_radix(radix),
self.im.to_str_radix(radix))
}
}
}
#[cfg(test)]
mod test {
#![allow(non_uppercase_statics)]
use super::{Complex64, Complex};
use std::num::{Zero, One, Float};
use std::hash::hash;
pub const _0_0i : Complex64 = Complex { re: 0.0, im: 0.0 };
pub const _1_0i : Complex64 = Complex { re: 1.0, im: 0.0 };
pub const _1_1i : Complex64 = Complex { re: 1.0, im: 1.0 };
pub const _0_1i : Complex64 = Complex { re: 0.0, im: 1.0 };
pub const _neg1_1i : Complex64 = Complex { re: -1.0, im: 1.0 };
pub const _05_05i : Complex64 = Complex { re: 0.5, im: 0.5 };
pub const all_consts : [Complex64, .. 5] = [_0_0i, _1_0i, _1_1i, _neg1_1i, _05_05i];
#[test]
fn test_consts() {
// check our constants are what Complex::new creates
fn test(c : Complex64, r : f64, i: f64) {
assert_eq!(c, Complex::new(r,i));
}
test(_0_0i, 0.0, 0.0);
test(_1_0i, 1.0, 0.0);
test(_1_1i, 1.0, 1.0);
test(_neg1_1i, -1.0, 1.0);
test(_05_05i, 0.5, 0.5);
assert_eq!(_0_0i, Zero::zero());
assert_eq!(_1_0i, One::one());
}
#[test]
#[cfg_attr(target_arch = "x86", ignore)]
// FIXME #7158: (maybe?) currently failing on x86.
fn test_norm() {
fn test(c: Complex64, ns: f64) {
assert_eq!(c.norm_sqr(), ns);
assert_eq!(c.norm(), ns.sqrt())
}
test(_0_0i, 0.0);
test(_1_0i, 1.0);
test(_1_1i, 2.0);
test(_neg1_1i, 2.0);
test(_05_05i, 0.5);
}
#[test]
fn test_scale_unscale() {
assert_eq!(_05_05i.scale(2.0), _1_1i);
assert_eq!(_1_1i.unscale(2.0), _05_05i);
for &c in all_consts.iter() {
assert_eq!(c.scale(2.0).unscale(2.0), c);
}
}
#[test]
fn test_conj() {
for &c in all_consts.iter() {
assert_eq!(c.conj(), Complex::new(c.re, -c.im));
assert_eq!(c.conj().conj(), c);
}
}
#[test]
fn test_inv() {
assert_eq!(_1_1i.inv(), _05_05i.conj());
assert_eq!(_1_0i.inv(), _1_0i.inv());
}
#[test]
#[should_fail]
fn test_divide_by_zero_natural() {
let n = Complex::new(2i, 3i);
let d = Complex::new(0, 0);
let _x = n / d;
}
#[test]
#[should_fail]
#[ignore]
fn test_inv_zero() {
// FIXME #5736: should this really fail, or just NaN?
_0_0i.inv();
}
#[test]
fn test_arg() {
fn test(c: Complex64, arg: f64) {
assert!((c.arg() - arg).abs() < 1.0e-6)
}
test(_1_0i, 0.0);
test(_1_1i, 0.25 * Float::pi());
test(_neg1_1i, 0.75 * Float::pi());
test(_05_05i, 0.25 * Float::pi());
}
#[test]
fn test_polar_conv() {
fn test(c: Complex64) {
let (r, theta) = c.to_polar();
assert!((c - Complex::from_polar(&r, &theta)).norm() < 1e-6);
}
for &c in all_consts.iter() { test(c); }
}
mod arith {
use super::{_0_0i, _1_0i, _1_1i, _0_1i, _neg1_1i, _05_05i, all_consts};
use std::num::Zero;
#[test]
fn test_add() {
assert_eq!(_05_05i + _05_05i, _1_1i);
assert_eq!(_0_1i + _1_0i, _1_1i);
assert_eq!(_1_0i + _neg1_1i, _0_1i);
for &c in all_consts.iter() {
assert_eq!(_0_0i + c, c);
assert_eq!(c + _0_0i, c);
}
}
#[test]
fn test_sub() {
assert_eq!(_05_05i - _05_05i, _0_0i);
assert_eq!(_0_1i - _1_0i, _neg1_1i);
assert_eq!(_0_1i - _neg1_1i, _1_0i);
for &c in all_consts.iter() {
assert_eq!(c - _0_0i, c);
assert_eq!(c - c, _0_0i);
}
}
#[test]
fn test_mul() {
assert_eq!(_05_05i * _05_05i, _0_1i.unscale(2.0));
assert_eq!(_1_1i * _0_1i, _neg1_1i);
// i^2 & i^4
assert_eq!(_0_1i * _0_1i, -_1_0i);
assert_eq!(_0_1i * _0_1i * _0_1i * _0_1i, _1_0i);
for &c in all_consts.iter() {
assert_eq!(c * _1_0i, c);
assert_eq!(_1_0i * c, c);
}
}
#[test]
fn test_div() {
assert_eq!(_neg1_1i / _0_1i, _1_1i);
for &c in all_consts.iter() {
if c != Zero::zero() {
assert_eq!(c / c, _1_0i);
}
}
}
#[test]
fn test_neg() {
assert_eq!(-_1_0i + _0_1i, _neg1_1i);
assert_eq!((-_0_1i) * _0_1i, _1_0i);
for &c in all_consts.iter() {
assert_eq!(-(-c), c);
}
}
}
#[test]
fn test_to_string() {
fn test(c : Complex64, s: String) {
assert_eq!(c.to_string(), s);
}
test(_0_0i, "0+0i".to_string());
test(_1_0i, "1+0i".to_string());
test(_0_1i, "0+1i".to_string());
test(_1_1i, "1+1i".to_string());
test(_neg1_1i, "-1+1i".to_string());
test(-_neg1_1i, "1-1i".to_string());
test(_05_05i, "0.5+0.5i".to_string());
}
#[test]
fn test_hash() {
let a = Complex::new(0i32, 0i32);
let b = Complex::new(1i32, 0i32);
let c = Complex::new(0i32, 1i32);
assert!(hash(&a) != hash(&b));
assert!(hash(&b) != hash(&c));
assert!(hash(&c) != hash(&a));
}
}

View File

@ -1,507 +0,0 @@
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Integer trait and functions.
pub trait Integer: Num + PartialOrd
+ Div<Self, Self>
+ Rem<Self, Self> {
/// Floored integer division.
///
/// # Examples
///
/// ```
/// # #![allow(deprecated)]
/// # use num::Integer;
/// assert!(( 8i).div_floor(& 3) == 2);
/// assert!(( 8i).div_floor(&-3) == -3);
/// assert!((-8i).div_floor(& 3) == -3);
/// assert!((-8i).div_floor(&-3) == 2);
///
/// assert!(( 1i).div_floor(& 2) == 0);
/// assert!(( 1i).div_floor(&-2) == -1);
/// assert!((-1i).div_floor(& 2) == -1);
/// assert!((-1i).div_floor(&-2) == 0);
/// ```
fn div_floor(&self, other: &Self) -> Self;
/// Floored integer modulo, satisfying:
///
/// ```
/// # #![allow(deprecated)]
/// # use num::Integer;
/// # let n = 1i; let d = 1i;
/// assert!(n.div_floor(&d) * d + n.mod_floor(&d) == n)
/// ```
///
/// # Examples
///
/// ```
/// # #![allow(deprecated)]
/// # use num::Integer;
/// assert!(( 8i).mod_floor(& 3) == 2);
/// assert!(( 8i).mod_floor(&-3) == -1);
/// assert!((-8i).mod_floor(& 3) == 1);
/// assert!((-8i).mod_floor(&-3) == -2);
///
/// assert!(( 1i).mod_floor(& 2) == 1);
/// assert!(( 1i).mod_floor(&-2) == -1);
/// assert!((-1i).mod_floor(& 2) == 1);
/// assert!((-1i).mod_floor(&-2) == -1);
/// ```
fn mod_floor(&self, other: &Self) -> Self;
/// Greatest Common Divisor (GCD).
///
/// # Examples
///
/// ```
/// # #![allow(deprecated)]
/// # use num::Integer;
/// assert_eq!(6i.gcd(&8), 2);
/// assert_eq!(7i.gcd(&3), 1);
/// ```
fn gcd(&self, other: &Self) -> Self;
/// Lowest Common Multiple (LCM).
///
/// # Examples
///
/// ```
/// # #![allow(deprecated)]
/// # use num::Integer;
/// assert_eq!(7i.lcm(&3), 21);
/// assert_eq!(2i.lcm(&4), 4);
/// ```
fn lcm(&self, other: &Self) -> Self;
/// Deprecated, use `is_multiple_of` instead.
#[deprecated = "function renamed to `is_multiple_of`"]
fn divides(&self, other: &Self) -> bool;
/// Returns `true` if `other` is a multiple of `self`.
///
/// # Examples
///
/// ```
/// # #![allow(deprecated)]
/// # use num::Integer;
/// assert_eq!(9i.is_multiple_of(&3), true);
/// assert_eq!(3i.is_multiple_of(&9), false);
/// ```
fn is_multiple_of(&self, other: &Self) -> bool;
/// Returns `true` if the number is even.
///
/// # Examples
///
/// ```
/// # #![allow(deprecated)]
/// # use num::Integer;
/// assert_eq!(3i.is_even(), false);
/// assert_eq!(4i.is_even(), true);
/// ```
fn is_even(&self) -> bool;
/// Returns `true` if the number is odd.
///
/// # Examples
///
/// ```
/// # #![allow(deprecated)]
/// # use num::Integer;
/// assert_eq!(3i.is_odd(), true);
/// assert_eq!(4i.is_odd(), false);
/// ```
fn is_odd(&self) -> bool;
/// Simultaneous truncated integer division and modulus.
/// Returns `(quotient, remainder)`.
///
/// # Examples
///
/// ```
/// # #![allow(deprecated)]
/// # use num::Integer;
/// assert_eq!(( 8i).div_rem( &3), ( 2, 2));
/// assert_eq!(( 8i).div_rem(&-3), (-2, 2));
/// assert_eq!((-8i).div_rem( &3), (-2, -2));
/// assert_eq!((-8i).div_rem(&-3), ( 2, -2));
///
/// assert_eq!(( 1i).div_rem( &2), ( 0, 1));
/// assert_eq!(( 1i).div_rem(&-2), ( 0, 1));
/// assert_eq!((-1i).div_rem( &2), ( 0, -1));
/// assert_eq!((-1i).div_rem(&-2), ( 0, -1));
/// ```
#[inline]
fn div_rem(&self, other: &Self) -> (Self, Self) {
(*self / *other, *self % *other)
}
/// Simultaneous floored integer division and modulus.
/// Returns `(quotient, remainder)`.
///
/// # Examples
///
/// ```
/// # #![allow(deprecated)]
/// # use num::Integer;
/// assert_eq!(( 8i).div_mod_floor( &3), ( 2, 2));
/// assert_eq!(( 8i).div_mod_floor(&-3), (-3, -1));
/// assert_eq!((-8i).div_mod_floor( &3), (-3, 1));
/// assert_eq!((-8i).div_mod_floor(&-3), ( 2, -2));
///
/// assert_eq!(( 1i).div_mod_floor( &2), ( 0, 1));
/// assert_eq!(( 1i).div_mod_floor(&-2), (-1, -1));
/// assert_eq!((-1i).div_mod_floor( &2), (-1, 1));
/// assert_eq!((-1i).div_mod_floor(&-2), ( 0, -1));
/// ```
fn div_mod_floor(&self, other: &Self) -> (Self, Self) {
(self.div_floor(other), self.mod_floor(other))
}
}
/// Simultaneous integer division and modulus
#[inline] pub fn div_rem<T: Integer>(x: T, y: T) -> (T, T) { x.div_rem(&y) }
/// Floored integer division
#[inline] pub fn div_floor<T: Integer>(x: T, y: T) -> T { x.div_floor(&y) }
/// Floored integer modulus
#[inline] pub fn mod_floor<T: Integer>(x: T, y: T) -> T { x.mod_floor(&y) }
/// Simultaneous floored integer division and modulus
#[inline] pub fn div_mod_floor<T: Integer>(x: T, y: T) -> (T, T) { x.div_mod_floor(&y) }
/// Calculates the Greatest Common Divisor (GCD) of the number and `other`. The
/// result is always positive.
#[inline(always)] pub fn gcd<T: Integer>(x: T, y: T) -> T { x.gcd(&y) }
/// Calculates the Lowest Common Multiple (LCM) of the number and `other`.
#[inline(always)] pub fn lcm<T: Integer>(x: T, y: T) -> T { x.lcm(&y) }
macro_rules! impl_integer_for_int {
($T:ty, $test_mod:ident) => (
impl Integer for $T {
/// Floored integer division
#[inline]
fn div_floor(&self, other: &$T) -> $T {
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
match self.div_rem(other) {
(d, r) if (r > 0 && *other < 0)
|| (r < 0 && *other > 0) => d - 1,
(d, _) => d,
}
}
/// Floored integer modulo
#[inline]
fn mod_floor(&self, other: &$T) -> $T {
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
match *self % *other {
r if (r > 0 && *other < 0)
|| (r < 0 && *other > 0) => r + *other,
r => r,
}
}
/// Calculates `div_floor` and `mod_floor` simultaneously
#[inline]
fn div_mod_floor(&self, other: &$T) -> ($T,$T) {
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
match self.div_rem(other) {
(d, r) if (r > 0 && *other < 0)
|| (r < 0 && *other > 0) => (d - 1, r + *other),
(d, r) => (d, r),
}
}
/// Calculates the Greatest Common Divisor (GCD) of the number and
/// `other`. The result is always positive.
#[inline]
fn gcd(&self, other: &$T) -> $T {
// Use Euclid's algorithm
let mut m = *self;
let mut n = *other;
while m != 0 {
let temp = m;
m = n % temp;
n = temp;
}
n.abs()
}
/// Calculates the Lowest Common Multiple (LCM) of the number and
/// `other`.
#[inline]
fn lcm(&self, other: &$T) -> $T {
// should not have to recalculate abs
((*self * *other) / self.gcd(other)).abs()
}
/// Deprecated, use `is_multiple_of` instead.
#[deprecated = "function renamed to `is_multiple_of`"]
#[inline]
fn divides(&self, other: &$T) -> bool { return self.is_multiple_of(other); }
/// Returns `true` if the number is a multiple of `other`.
#[inline]
fn is_multiple_of(&self, other: &$T) -> bool { *self % *other == 0 }
/// Returns `true` if the number is divisible by `2`
#[inline]
fn is_even(&self) -> bool { self & 1 == 0 }
/// Returns `true` if the number is not divisible by `2`
#[inline]
fn is_odd(&self) -> bool { !self.is_even() }
}
#[cfg(test)]
mod $test_mod {
use Integer;
/// Checks that the division rule holds for:
///
/// - `n`: numerator (dividend)
/// - `d`: denominator (divisor)
/// - `qr`: quotient and remainder
#[cfg(test)]
fn test_division_rule((n,d): ($T,$T), (q,r): ($T,$T)) {
assert_eq!(d * q + r, n);
}
#[test]
fn test_div_rem() {
fn test_nd_dr(nd: ($T,$T), qr: ($T,$T)) {
let (n,d) = nd;
let separate_div_rem = (n / d, n % d);
let combined_div_rem = n.div_rem(&d);
assert_eq!(separate_div_rem, qr);
assert_eq!(combined_div_rem, qr);
test_division_rule(nd, separate_div_rem);
test_division_rule(nd, combined_div_rem);
}
test_nd_dr(( 8, 3), ( 2, 2));
test_nd_dr(( 8, -3), (-2, 2));
test_nd_dr((-8, 3), (-2, -2));
test_nd_dr((-8, -3), ( 2, -2));
test_nd_dr(( 1, 2), ( 0, 1));
test_nd_dr(( 1, -2), ( 0, 1));
test_nd_dr((-1, 2), ( 0, -1));
test_nd_dr((-1, -2), ( 0, -1));
}
#[test]
fn test_div_mod_floor() {
fn test_nd_dm(nd: ($T,$T), dm: ($T,$T)) {
let (n,d) = nd;
let separate_div_mod_floor = (n.div_floor(&d), n.mod_floor(&d));
let combined_div_mod_floor = n.div_mod_floor(&d);
assert_eq!(separate_div_mod_floor, dm);
assert_eq!(combined_div_mod_floor, dm);
test_division_rule(nd, separate_div_mod_floor);
test_division_rule(nd, combined_div_mod_floor);
}
test_nd_dm(( 8, 3), ( 2, 2));
test_nd_dm(( 8, -3), (-3, -1));
test_nd_dm((-8, 3), (-3, 1));
test_nd_dm((-8, -3), ( 2, -2));
test_nd_dm(( 1, 2), ( 0, 1));
test_nd_dm(( 1, -2), (-1, -1));
test_nd_dm((-1, 2), (-1, 1));
test_nd_dm((-1, -2), ( 0, -1));
}
#[test]
fn test_gcd() {
assert_eq!((10 as $T).gcd(&2), 2 as $T);
assert_eq!((10 as $T).gcd(&3), 1 as $T);
assert_eq!((0 as $T).gcd(&3), 3 as $T);
assert_eq!((3 as $T).gcd(&3), 3 as $T);
assert_eq!((56 as $T).gcd(&42), 14 as $T);
assert_eq!((3 as $T).gcd(&-3), 3 as $T);
assert_eq!((-6 as $T).gcd(&3), 3 as $T);
assert_eq!((-4 as $T).gcd(&-2), 2 as $T);
}
#[test]
fn test_lcm() {
assert_eq!((1 as $T).lcm(&0), 0 as $T);
assert_eq!((0 as $T).lcm(&1), 0 as $T);
assert_eq!((1 as $T).lcm(&1), 1 as $T);
assert_eq!((-1 as $T).lcm(&1), 1 as $T);
assert_eq!((1 as $T).lcm(&-1), 1 as $T);
assert_eq!((-1 as $T).lcm(&-1), 1 as $T);
assert_eq!((8 as $T).lcm(&9), 72 as $T);
assert_eq!((11 as $T).lcm(&5), 55 as $T);
}
#[test]
fn test_even() {
assert_eq!((-4 as $T).is_even(), true);
assert_eq!((-3 as $T).is_even(), false);
assert_eq!((-2 as $T).is_even(), true);
assert_eq!((-1 as $T).is_even(), false);
assert_eq!((0 as $T).is_even(), true);
assert_eq!((1 as $T).is_even(), false);
assert_eq!((2 as $T).is_even(), true);
assert_eq!((3 as $T).is_even(), false);
assert_eq!((4 as $T).is_even(), true);
}
#[test]
fn test_odd() {
assert_eq!((-4 as $T).is_odd(), false);
assert_eq!((-3 as $T).is_odd(), true);
assert_eq!((-2 as $T).is_odd(), false);
assert_eq!((-1 as $T).is_odd(), true);
assert_eq!((0 as $T).is_odd(), false);
assert_eq!((1 as $T).is_odd(), true);
assert_eq!((2 as $T).is_odd(), false);
assert_eq!((3 as $T).is_odd(), true);
assert_eq!((4 as $T).is_odd(), false);
}
}
)
}
impl_integer_for_int!(i8, test_integer_i8)
impl_integer_for_int!(i16, test_integer_i16)
impl_integer_for_int!(i32, test_integer_i32)
impl_integer_for_int!(i64, test_integer_i64)
impl_integer_for_int!(int, test_integer_int)
macro_rules! impl_integer_for_uint {
($T:ty, $test_mod:ident) => (
impl Integer for $T {
/// Unsigned integer division. Returns the same result as `div` (`/`).
#[inline]
fn div_floor(&self, other: &$T) -> $T { *self / *other }
/// Unsigned integer modulo operation. Returns the same result as `rem` (`%`).
#[inline]
fn mod_floor(&self, other: &$T) -> $T { *self % *other }
/// Calculates the Greatest Common Divisor (GCD) of the number and `other`
#[inline]
fn gcd(&self, other: &$T) -> $T {
// Use Euclid's algorithm
let mut m = *self;
let mut n = *other;
while m != 0 {
let temp = m;
m = n % temp;
n = temp;
}
n
}
/// Calculates the Lowest Common Multiple (LCM) of the number and `other`.
#[inline]
fn lcm(&self, other: &$T) -> $T {
(*self * *other) / self.gcd(other)
}
/// Deprecated, use `is_multiple_of` instead.
#[deprecated = "function renamed to `is_multiple_of`"]
#[inline]
fn divides(&self, other: &$T) -> bool { return self.is_multiple_of(other); }
/// Returns `true` if the number is a multiple of `other`.
#[inline]
fn is_multiple_of(&self, other: &$T) -> bool { *self % *other == 0 }
/// Returns `true` if the number is divisible by `2`.
#[inline]
fn is_even(&self) -> bool { self & 1 == 0 }
/// Returns `true` if the number is not divisible by `2`.
#[inline]
fn is_odd(&self) -> bool { !self.is_even() }
}
#[cfg(test)]
mod $test_mod {
use Integer;
#[test]
fn test_div_mod_floor() {
assert_eq!((10 as $T).div_floor(&(3 as $T)), 3 as $T);
assert_eq!((10 as $T).mod_floor(&(3 as $T)), 1 as $T);
assert_eq!((10 as $T).div_mod_floor(&(3 as $T)), (3 as $T, 1 as $T));
assert_eq!((5 as $T).div_floor(&(5 as $T)), 1 as $T);
assert_eq!((5 as $T).mod_floor(&(5 as $T)), 0 as $T);
assert_eq!((5 as $T).div_mod_floor(&(5 as $T)), (1 as $T, 0 as $T));
assert_eq!((3 as $T).div_floor(&(7 as $T)), 0 as $T);
assert_eq!((3 as $T).mod_floor(&(7 as $T)), 3 as $T);
assert_eq!((3 as $T).div_mod_floor(&(7 as $T)), (0 as $T, 3 as $T));
}
#[test]
fn test_gcd() {
assert_eq!((10 as $T).gcd(&2), 2 as $T);
assert_eq!((10 as $T).gcd(&3), 1 as $T);
assert_eq!((0 as $T).gcd(&3), 3 as $T);
assert_eq!((3 as $T).gcd(&3), 3 as $T);
assert_eq!((56 as $T).gcd(&42), 14 as $T);
}
#[test]
#[allow(type_overflow)]
fn test_lcm() {
assert_eq!((1 as $T).lcm(&0), 0 as $T);
assert_eq!((0 as $T).lcm(&1), 0 as $T);
assert_eq!((1 as $T).lcm(&1), 1 as $T);
assert_eq!((8 as $T).lcm(&9), 72 as $T);
assert_eq!((11 as $T).lcm(&5), 55 as $T);
assert_eq!((99 as $T).lcm(&17), 1683 as $T);
}
#[test]
fn test_is_multiple_of() {
assert!((6 as $T).is_multiple_of(&(6 as $T)));
assert!((6 as $T).is_multiple_of(&(3 as $T)));
assert!((6 as $T).is_multiple_of(&(1 as $T)));
}
#[test]
fn test_even() {
assert_eq!((0 as $T).is_even(), true);
assert_eq!((1 as $T).is_even(), false);
assert_eq!((2 as $T).is_even(), true);
assert_eq!((3 as $T).is_even(), false);
assert_eq!((4 as $T).is_even(), true);
}
#[test]
fn test_odd() {
assert_eq!((0 as $T).is_odd(), false);
assert_eq!((1 as $T).is_odd(), true);
assert_eq!((2 as $T).is_odd(), false);
assert_eq!((3 as $T).is_odd(), true);
assert_eq!((4 as $T).is_odd(), false);
}
}
)
}
impl_integer_for_uint!(u8, test_integer_u8)
impl_integer_for_uint!(u16, test_integer_u16)
impl_integer_for_uint!(u32, test_integer_u32)
impl_integer_for_uint!(u64, test_integer_u64)
impl_integer_for_uint!(uint, test_integer_uint)

View File

@ -1,73 +0,0 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Simple numerics.
//!
//! This crate contains arbitrary-sized integer, rational, and complex types.
//!
//! ## Example
//!
//! This example uses the BigRational type and [Newton's method][newt] to
//! approximate a square root to arbitrary precision:
//!
//! ```
//! # #![allow(deprecated)]
//! extern crate num;
//!
//! use num::bigint::BigInt;
//! use num::rational::{Ratio, BigRational};
//!
//! fn approx_sqrt(number: u64, iterations: uint) -> BigRational {
//! let start: Ratio<BigInt> = Ratio::from_integer(FromPrimitive::from_u64(number).unwrap());
//! let mut approx = start.clone();
//!
//! for _ in range(0, iterations) {
//! approx = (approx + (start / approx)) /
//! Ratio::from_integer(FromPrimitive::from_u64(2).unwrap());
//! }
//!
//! approx
//! }
//!
//! fn main() {
//! println!("{}", approx_sqrt(10, 4)); // prints 4057691201/1283082416
//! }
//! ```
//!
//! [newt]: https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method
#![allow(unknown_features)]
#![feature(macro_rules, slicing_syntax)]
#![feature(default_type_params)]
#![crate_name = "num"]
#![deprecated = "This is now a cargo package located at: \
https://github.com/rust-lang/num"]
#![allow(deprecated)]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/",
html_playground_url = "http://play.rust-lang.org/")]
#![allow(deprecated)] // from_str_radix
extern crate rand;
pub use bigint::{BigInt, BigUint};
pub use rational::{Rational, BigRational};
pub use complex::Complex;
pub use integer::Integer;
pub mod bigint;
pub mod complex;
pub mod integer;
pub mod rational;

View File

@ -1,803 +0,0 @@
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Rational numbers
use Integer;
use std::cmp;
use std::fmt;
use std::from_str::FromStr;
use std::num;
use std::num::{Zero, One, ToStrRadix, FromStrRadix};
use bigint::{BigInt, BigUint, Sign, Plus, Minus};
/// Represents the ratio between 2 numbers.
#[deriving(Clone, Hash)]
#[allow(missing_doc)]
pub struct Ratio<T> {
numer: T,
denom: T
}
/// Alias for a `Ratio` of machine-sized integers.
pub type Rational = Ratio<int>;
pub type Rational32 = Ratio<i32>;
pub type Rational64 = Ratio<i64>;
/// Alias for arbitrary precision rationals.
pub type BigRational = Ratio<BigInt>;
impl<T: Clone + Integer + PartialOrd>
Ratio<T> {
/// Creates a ratio representing the integer `t`.
#[inline]
pub fn from_integer(t: T) -> Ratio<T> {
Ratio::new_raw(t, One::one())
}
/// Creates a ratio without checking for `denom == 0` or reducing.
#[inline]
pub fn new_raw(numer: T, denom: T) -> Ratio<T> {
Ratio { numer: numer, denom: denom }
}
/// Create a new Ratio. Fails if `denom == 0`.
#[inline]
pub fn new(numer: T, denom: T) -> Ratio<T> {
if denom == Zero::zero() {
fail!("denominator == 0");
}
let mut ret = Ratio::new_raw(numer, denom);
ret.reduce();
ret
}
/// Converts to an integer.
#[inline]
pub fn to_integer(&self) -> T {
self.trunc().numer
}
/// Gets an immutable reference to the numerator.
#[inline]
pub fn numer<'a>(&'a self) -> &'a T {
&self.numer
}
/// Gets an immutable reference to the denominator.
#[inline]
pub fn denom<'a>(&'a self) -> &'a T {
&self.denom
}
/// Returns true if the rational number is an integer (denominator is 1).
#[inline]
pub fn is_integer(&self) -> bool {
self.denom == One::one()
}
/// Put self into lowest terms, with denom > 0.
fn reduce(&mut self) {
let g : T = self.numer.gcd(&self.denom);
// FIXME(#5992): assignment operator overloads
// self.numer /= g;
self.numer = self.numer / g;
// FIXME(#5992): assignment operator overloads
// self.denom /= g;
self.denom = self.denom / g;
// keep denom positive!
if self.denom < Zero::zero() {
self.numer = -self.numer;
self.denom = -self.denom;
}
}
/// Returns a `reduce`d copy of self.
pub fn reduced(&self) -> Ratio<T> {
let mut ret = self.clone();
ret.reduce();
ret
}
/// Returns the reciprocal.
#[inline]
pub fn recip(&self) -> Ratio<T> {
Ratio::new_raw(self.denom.clone(), self.numer.clone())
}
/// Rounds towards minus infinity.
#[inline]
pub fn floor(&self) -> Ratio<T> {
if *self < Zero::zero() {
Ratio::from_integer((self.numer - self.denom + One::one()) / self.denom)
} else {
Ratio::from_integer(self.numer / self.denom)
}
}
/// Rounds towards plus infinity.
#[inline]
pub fn ceil(&self) -> Ratio<T> {
if *self < Zero::zero() {
Ratio::from_integer(self.numer / self.denom)
} else {
Ratio::from_integer((self.numer + self.denom - One::one()) / self.denom)
}
}
/// Rounds to the nearest integer. Rounds half-way cases away from zero.
#[inline]
pub fn round(&self) -> Ratio<T> {
let one: T = One::one();
let two: T = one + one;
// Find unsigned fractional part of rational number
let fractional = self.fract().abs();
// The algorithm compares the unsigned fractional part with 1/2, that
// is, a/b >= 1/2, or a >= b/2. For odd denominators, we use
// a >= (b/2)+1. This avoids overflow issues.
let half_or_larger = if fractional.denom().is_even() {
*fractional.numer() >= *fractional.denom() / two
} else {
*fractional.numer() >= (*fractional.denom() / two) + one
};
if half_or_larger {
if *self >= Zero::zero() {
self.trunc() + One::one()
} else {
self.trunc() - One::one()
}
} else {
self.trunc()
}
}
/// Rounds towards zero.
#[inline]
pub fn trunc(&self) -> Ratio<T> {
Ratio::from_integer(self.numer / self.denom)
}
/// Returns the fractional part of a number.
#[inline]
pub fn fract(&self) -> Ratio<T> {
Ratio::new_raw(self.numer % self.denom, self.denom.clone())
}
}
impl Ratio<BigInt> {
/// Converts a float into a rational number.
pub fn from_float<T: Float>(f: T) -> Option<BigRational> {
if !f.is_finite() {
return None;
}
let (mantissa, exponent, sign) = f.integer_decode();
let bigint_sign: Sign = if sign == 1 { Plus } else { Minus };
if exponent < 0 {
let one: BigInt = One::one();
let denom: BigInt = one << ((-exponent) as uint);
let numer: BigUint = FromPrimitive::from_u64(mantissa).unwrap();
Some(Ratio::new(BigInt::from_biguint(bigint_sign, numer), denom))
} else {
let mut numer: BigUint = FromPrimitive::from_u64(mantissa).unwrap();
numer = numer << (exponent as uint);
Some(Ratio::from_integer(BigInt::from_biguint(bigint_sign, numer)))
}
}
}
/* Comparisons */
// comparing a/b and c/d is the same as comparing a*d and b*c, so we
// abstract that pattern. The following macro takes a trait and either
// a comma-separated list of "method name -> return value" or just
// "method name" (return value is bool in that case)
macro_rules! cmp_impl {
(impl $imp:ident, $($method:ident),+) => {
cmp_impl!(impl $imp, $($method -> bool),+)
};
// return something other than a Ratio<T>
(impl $imp:ident, $($method:ident -> $res:ty),*) => {
impl<T: Mul<T,T> + $imp> $imp for Ratio<T> {
$(
#[inline]
fn $method(&self, other: &Ratio<T>) -> $res {
(self.numer * other.denom). $method (&(self.denom*other.numer))
}
)*
}
};
}
cmp_impl!(impl PartialEq, eq, ne)
cmp_impl!(impl PartialOrd, lt -> bool, gt -> bool, le -> bool, ge -> bool,
partial_cmp -> Option<cmp::Ordering>)
cmp_impl!(impl Eq, )
cmp_impl!(impl Ord, cmp -> cmp::Ordering)
/* Arithmetic */
// a/b * c/d = (a*c)/(b*d)
impl<T: Clone + Integer + PartialOrd>
Mul<Ratio<T>,Ratio<T>> for Ratio<T> {
#[inline]
fn mul(&self, rhs: &Ratio<T>) -> Ratio<T> {
Ratio::new(self.numer * rhs.numer, self.denom * rhs.denom)
}
}
// (a/b) / (c/d) = (a*d)/(b*c)
impl<T: Clone + Integer + PartialOrd>
Div<Ratio<T>,Ratio<T>> for Ratio<T> {
#[inline]
fn div(&self, rhs: &Ratio<T>) -> Ratio<T> {
Ratio::new(self.numer * rhs.denom, self.denom * rhs.numer)
}
}
// Abstracts the a/b `op` c/d = (a*d `op` b*d) / (b*d) pattern
macro_rules! arith_impl {
(impl $imp:ident, $method:ident) => {
impl<T: Clone + Integer + PartialOrd>
$imp<Ratio<T>,Ratio<T>> for Ratio<T> {
#[inline]
fn $method(&self, rhs: &Ratio<T>) -> Ratio<T> {
Ratio::new((self.numer * rhs.denom).$method(&(self.denom * rhs.numer)),
self.denom * rhs.denom)
}
}
}
}
// a/b + c/d = (a*d + b*c)/(b*d)
arith_impl!(impl Add, add)
// a/b - c/d = (a*d - b*c)/(b*d)
arith_impl!(impl Sub, sub)
// a/b % c/d = (a*d % b*c)/(b*d)
arith_impl!(impl Rem, rem)
impl<T: Clone + Integer + PartialOrd>
Neg<Ratio<T>> for Ratio<T> {
#[inline]
fn neg(&self) -> Ratio<T> {
Ratio::new_raw(-self.numer, self.denom.clone())
}
}
/* Constants */
impl<T: Clone + Integer + PartialOrd>
Zero for Ratio<T> {
#[inline]
fn zero() -> Ratio<T> {
Ratio::new_raw(Zero::zero(), One::one())
}
#[inline]
fn is_zero(&self) -> bool {
*self == Zero::zero()
}
}
impl<T: Clone + Integer + PartialOrd>
One for Ratio<T> {
#[inline]
fn one() -> Ratio<T> {
Ratio::new_raw(One::one(), One::one())
}
}
impl<T: Clone + Integer + PartialOrd>
Num for Ratio<T> {}
impl<T: Clone + Integer + PartialOrd>
num::Signed for Ratio<T> {
#[inline]
fn abs(&self) -> Ratio<T> {
if self.is_negative() { -self.clone() } else { self.clone() }
}
#[inline]
fn abs_sub(&self, other: &Ratio<T>) -> Ratio<T> {
if *self <= *other { Zero::zero() } else { *self - *other }
}
#[inline]
fn signum(&self) -> Ratio<T> {
if *self > Zero::zero() {
num::one()
} else if self.is_zero() {
num::zero()
} else {
- num::one::<Ratio<T>>()
}
}
#[inline]
fn is_positive(&self) -> bool { *self > Zero::zero() }
#[inline]
fn is_negative(&self) -> bool { *self < Zero::zero() }
}
/* String conversions */
impl<T: fmt::Show + Eq + One> fmt::Show for Ratio<T> {
/// Renders as `numer/denom`. If denom=1, renders as numer.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.denom == One::one() {
write!(f, "{}", self.numer)
} else {
write!(f, "{}/{}", self.numer, self.denom)
}
}
}
impl<T: ToStrRadix> ToStrRadix for Ratio<T> {
/// Renders as `numer/denom` where the numbers are in base `radix`.
fn to_str_radix(&self, radix: uint) -> String {
format!("{}/{}",
self.numer.to_str_radix(radix),
self.denom.to_str_radix(radix))
}
}
impl<T: FromStr + Clone + Integer + PartialOrd>
FromStr for Ratio<T> {
/// Parses `numer/denom` or just `numer`.
fn from_str(s: &str) -> Option<Ratio<T>> {
let mut split = s.splitn(1, '/');
let num = split.next().and_then(|n| FromStr::from_str(n));
let den = split.next().or(Some("1")).and_then(|d| FromStr::from_str(d));
match (num, den) {
(Some(n), Some(d)) => Some(Ratio::new(n, d)),
_ => None
}
}
}
impl<T: FromStrRadix + Clone + Integer + PartialOrd>
FromStrRadix for Ratio<T> {
/// Parses `numer/denom` where the numbers are in base `radix`.
fn from_str_radix(s: &str, radix: uint) -> Option<Ratio<T>> {
let split: Vec<&str> = s.splitn(1, '/').collect();
if split.len() < 2 {
None
} else {
let a_option: Option<T> = FromStrRadix::from_str_radix(
*split.get(0),
radix);
a_option.and_then(|a| {
let b_option: Option<T> =
FromStrRadix::from_str_radix(*split.get(1), radix);
b_option.and_then(|b| {
Some(Ratio::new(a.clone(), b.clone()))
})
})
}
}
}
#[cfg(test)]
mod test {
use super::{Ratio, Rational, BigRational};
use std::num::{Zero, One, FromStrRadix, FromPrimitive, ToStrRadix};
use std::from_str::FromStr;
use std::hash::hash;
use std::num;
use std::i32;
pub static _0 : Rational = Ratio { numer: 0, denom: 1};
pub static _1 : Rational = Ratio { numer: 1, denom: 1};
pub static _2: Rational = Ratio { numer: 2, denom: 1};
pub static _1_2: Rational = Ratio { numer: 1, denom: 2};
pub static _3_2: Rational = Ratio { numer: 3, denom: 2};
#[allow(non_uppercase_statics)]
pub static _neg1_2: Rational = Ratio { numer: -1, denom: 2};
pub static _1_3: Rational = Ratio { numer: 1, denom: 3};
#[allow(non_uppercase_statics)]
pub static _neg1_3: Rational = Ratio { numer: -1, denom: 3};
pub static _2_3: Rational = Ratio { numer: 2, denom: 3};
#[allow(non_uppercase_statics)]
pub static _neg2_3: Rational = Ratio { numer: -2, denom: 3};
pub fn to_big(n: Rational) -> BigRational {
Ratio::new(
FromPrimitive::from_int(n.numer).unwrap(),
FromPrimitive::from_int(n.denom).unwrap()
)
}
#[test]
fn test_test_constants() {
// check our constants are what Ratio::new etc. would make.
assert_eq!(_0, Zero::zero());
assert_eq!(_1, One::one());
assert_eq!(_2, Ratio::from_integer(2i));
assert_eq!(_1_2, Ratio::new(1i,2i));
assert_eq!(_3_2, Ratio::new(3i,2i));
assert_eq!(_neg1_2, Ratio::new(-1i,2i));
}
#[test]
fn test_new_reduce() {
let one22 = Ratio::new(2i,2);
assert_eq!(one22, One::one());
}
#[test]
#[should_fail]
fn test_new_zero() {
let _a = Ratio::new(1i,0);
}
#[test]
fn test_cmp() {
assert!(_0 == _0 && _1 == _1);
assert!(_0 != _1 && _1 != _0);
assert!(_0 < _1 && !(_1 < _0));
assert!(_1 > _0 && !(_0 > _1));
assert!(_0 <= _0 && _1 <= _1);
assert!(_0 <= _1 && !(_1 <= _0));
assert!(_0 >= _0 && _1 >= _1);
assert!(_1 >= _0 && !(_0 >= _1));
}
#[test]
fn test_to_integer() {
assert_eq!(_0.to_integer(), 0);
assert_eq!(_1.to_integer(), 1);
assert_eq!(_2.to_integer(), 2);
assert_eq!(_1_2.to_integer(), 0);
assert_eq!(_3_2.to_integer(), 1);
assert_eq!(_neg1_2.to_integer(), 0);
}
#[test]
fn test_numer() {
assert_eq!(_0.numer(), &0);
assert_eq!(_1.numer(), &1);
assert_eq!(_2.numer(), &2);
assert_eq!(_1_2.numer(), &1);
assert_eq!(_3_2.numer(), &3);
assert_eq!(_neg1_2.numer(), &(-1));
}
#[test]
fn test_denom() {
assert_eq!(_0.denom(), &1);
assert_eq!(_1.denom(), &1);
assert_eq!(_2.denom(), &1);
assert_eq!(_1_2.denom(), &2);
assert_eq!(_3_2.denom(), &2);
assert_eq!(_neg1_2.denom(), &2);
}
#[test]
fn test_is_integer() {
assert!(_0.is_integer());
assert!(_1.is_integer());
assert!(_2.is_integer());
assert!(!_1_2.is_integer());
assert!(!_3_2.is_integer());
assert!(!_neg1_2.is_integer());
}
#[test]
fn test_show() {
assert_eq!(format!("{}", _2), "2".to_string());
assert_eq!(format!("{}", _1_2), "1/2".to_string());
assert_eq!(format!("{}", _0), "0".to_string());
assert_eq!(format!("{}", Ratio::from_integer(-2i)), "-2".to_string());
}
mod arith {
use super::{_0, _1, _2, _1_2, _3_2, _neg1_2, to_big};
use super::super::{Ratio, Rational};
#[test]
fn test_add() {
fn test(a: Rational, b: Rational, c: Rational) {
assert_eq!(a + b, c);
assert_eq!(to_big(a) + to_big(b), to_big(c));
}
test(_1, _1_2, _3_2);
test(_1, _1, _2);
test(_1_2, _3_2, _2);
test(_1_2, _neg1_2, _0);
}
#[test]
fn test_sub() {
fn test(a: Rational, b: Rational, c: Rational) {
assert_eq!(a - b, c);
assert_eq!(to_big(a) - to_big(b), to_big(c))
}
test(_1, _1_2, _1_2);
test(_3_2, _1_2, _1);
test(_1, _neg1_2, _3_2);
}
#[test]
fn test_mul() {
fn test(a: Rational, b: Rational, c: Rational) {
assert_eq!(a * b, c);
assert_eq!(to_big(a) * to_big(b), to_big(c))
}
test(_1, _1_2, _1_2);
test(_1_2, _3_2, Ratio::new(3i,4i));
test(_1_2, _neg1_2, Ratio::new(-1i, 4i));
}
#[test]
fn test_div() {
fn test(a: Rational, b: Rational, c: Rational) {
assert_eq!(a / b, c);
assert_eq!(to_big(a) / to_big(b), to_big(c))
}
test(_1, _1_2, _2);
test(_3_2, _1_2, _1 + _2);
test(_1, _neg1_2, _neg1_2 + _neg1_2 + _neg1_2 + _neg1_2);
}
#[test]
fn test_rem() {
fn test(a: Rational, b: Rational, c: Rational) {
assert_eq!(a % b, c);
assert_eq!(to_big(a) % to_big(b), to_big(c))
}
test(_3_2, _1, _1_2);
test(_2, _neg1_2, _0);
test(_1_2, _2, _1_2);
}
#[test]
fn test_neg() {
fn test(a: Rational, b: Rational) {
assert_eq!(-a, b);
assert_eq!(-to_big(a), to_big(b))
}
test(_0, _0);
test(_1_2, _neg1_2);
test(-_1, _1);
}
#[test]
fn test_zero() {
assert_eq!(_0 + _0, _0);
assert_eq!(_0 * _0, _0);
assert_eq!(_0 * _1, _0);
assert_eq!(_0 / _neg1_2, _0);
assert_eq!(_0 - _0, _0);
}
#[test]
#[should_fail]
fn test_div_0() {
let _a = _1 / _0;
}
}
#[test]
fn test_round() {
assert_eq!(_1_3.ceil(), _1);
assert_eq!(_1_3.floor(), _0);
assert_eq!(_1_3.round(), _0);
assert_eq!(_1_3.trunc(), _0);
assert_eq!(_neg1_3.ceil(), _0);
assert_eq!(_neg1_3.floor(), -_1);
assert_eq!(_neg1_3.round(), _0);
assert_eq!(_neg1_3.trunc(), _0);
assert_eq!(_2_3.ceil(), _1);
assert_eq!(_2_3.floor(), _0);
assert_eq!(_2_3.round(), _1);
assert_eq!(_2_3.trunc(), _0);
assert_eq!(_neg2_3.ceil(), _0);
assert_eq!(_neg2_3.floor(), -_1);
assert_eq!(_neg2_3.round(), -_1);
assert_eq!(_neg2_3.trunc(), _0);
assert_eq!(_1_2.ceil(), _1);
assert_eq!(_1_2.floor(), _0);
assert_eq!(_1_2.round(), _1);
assert_eq!(_1_2.trunc(), _0);
assert_eq!(_neg1_2.ceil(), _0);
assert_eq!(_neg1_2.floor(), -_1);
assert_eq!(_neg1_2.round(), -_1);
assert_eq!(_neg1_2.trunc(), _0);
assert_eq!(_1.ceil(), _1);
assert_eq!(_1.floor(), _1);
assert_eq!(_1.round(), _1);
assert_eq!(_1.trunc(), _1);
// Overflow checks
let _neg1 = Ratio::from_integer(-1);
let _large_rat1 = Ratio::new(i32::MAX, i32::MAX-1);
let _large_rat2 = Ratio::new(i32::MAX-1, i32::MAX);
let _large_rat3 = Ratio::new(i32::MIN+2, i32::MIN+1);
let _large_rat4 = Ratio::new(i32::MIN+1, i32::MIN+2);
let _large_rat5 = Ratio::new(i32::MIN+2, i32::MAX);
let _large_rat6 = Ratio::new(i32::MAX, i32::MIN+2);
let _large_rat7 = Ratio::new(1, i32::MIN+1);
let _large_rat8 = Ratio::new(1, i32::MAX);
assert_eq!(_large_rat1.round(), One::one());
assert_eq!(_large_rat2.round(), One::one());
assert_eq!(_large_rat3.round(), One::one());
assert_eq!(_large_rat4.round(), One::one());
assert_eq!(_large_rat5.round(), _neg1);
assert_eq!(_large_rat6.round(), _neg1);
assert_eq!(_large_rat7.round(), Zero::zero());
assert_eq!(_large_rat8.round(), Zero::zero());
}
#[test]
fn test_fract() {
assert_eq!(_1.fract(), _0);
assert_eq!(_neg1_2.fract(), _neg1_2);
assert_eq!(_1_2.fract(), _1_2);
assert_eq!(_3_2.fract(), _1_2);
}
#[test]
fn test_recip() {
assert_eq!(_1 * _1.recip(), _1);
assert_eq!(_2 * _2.recip(), _1);
assert_eq!(_1_2 * _1_2.recip(), _1);
assert_eq!(_3_2 * _3_2.recip(), _1);
assert_eq!(_neg1_2 * _neg1_2.recip(), _1);
}
#[test]
fn test_to_from_str() {
fn test(r: Rational, s: String) {
assert_eq!(FromStr::from_str(s.as_slice()), Some(r));
assert_eq!(r.to_string(), s);
}
test(_1, "1".to_string());
test(_0, "0".to_string());
test(_1_2, "1/2".to_string());
test(_3_2, "3/2".to_string());
test(_2, "2".to_string());
test(_neg1_2, "-1/2".to_string());
}
#[test]
fn test_from_str_fail() {
fn test(s: &str) {
let rational: Option<Rational> = FromStr::from_str(s);
assert_eq!(rational, None);
}
let xs = ["0 /1", "abc", "", "1/", "--1/2","3/2/1"];
for &s in xs.iter() {
test(s);
}
}
#[test]
fn test_to_from_str_radix() {
fn test(r: Rational, s: String, n: uint) {
assert_eq!(FromStrRadix::from_str_radix(s.as_slice(), n),
Some(r));
assert_eq!(r.to_str_radix(n).to_string(), s);
}
fn test3(r: Rational, s: String) { test(r, s, 3) }
fn test16(r: Rational, s: String) { test(r, s, 16) }
test3(_1, "1/1".to_string());
test3(_0, "0/1".to_string());
test3(_1_2, "1/2".to_string());
test3(_3_2, "10/2".to_string());
test3(_2, "2/1".to_string());
test3(_neg1_2, "-1/2".to_string());
test3(_neg1_2 / _2, "-1/11".to_string());
test16(_1, "1/1".to_string());
test16(_0, "0/1".to_string());
test16(_1_2, "1/2".to_string());
test16(_3_2, "3/2".to_string());
test16(_2, "2/1".to_string());
test16(_neg1_2, "-1/2".to_string());
test16(_neg1_2 / _2, "-1/4".to_string());
test16(Ratio::new(13i,15i), "d/f".to_string());
test16(_1_2*_1_2*_1_2*_1_2, "1/10".to_string());
}
#[test]
fn test_from_str_radix_fail() {
fn test(s: &str) {
let radix: Option<Rational> = FromStrRadix::from_str_radix(s, 3);
assert_eq!(radix, None);
}
let xs = ["0 /1", "abc", "", "1/", "--1/2","3/2/1", "3/2"];
for &s in xs.iter() {
test(s);
}
}
#[test]
fn test_from_float() {
fn test<T: Float>(given: T, (numer, denom): (&str, &str)) {
let ratio: BigRational = Ratio::from_float(given).unwrap();
assert_eq!(ratio, Ratio::new(
FromStr::from_str(numer).unwrap(),
FromStr::from_str(denom).unwrap()));
}
// f32
test(3.14159265359f32, ("13176795", "4194304"));
test(2f32.powf(100.), ("1267650600228229401496703205376", "1"));
test(-2f32.powf(100.), ("-1267650600228229401496703205376", "1"));
test(1.0 / 2f32.powf(100.), ("1", "1267650600228229401496703205376"));
test(684729.48391f32, ("1369459", "2"));
test(-8573.5918555f32, ("-4389679", "512"));
// f64
test(3.14159265359f64, ("3537118876014453", "1125899906842624"));
test(2f64.powf(100.), ("1267650600228229401496703205376", "1"));
test(-2f64.powf(100.), ("-1267650600228229401496703205376", "1"));
test(684729.48391f64, ("367611342500051", "536870912"));
test(-8573.5918555f64, ("-4713381968463931", "549755813888"));
test(1.0 / 2f64.powf(100.), ("1", "1267650600228229401496703205376"));
}
#[test]
fn test_from_float_fail() {
use std::{f32, f64};
assert_eq!(Ratio::from_float(f32::NAN), None);
assert_eq!(Ratio::from_float(f32::INFINITY), None);
assert_eq!(Ratio::from_float(f32::NEG_INFINITY), None);
assert_eq!(Ratio::from_float(f64::NAN), None);
assert_eq!(Ratio::from_float(f64::INFINITY), None);
assert_eq!(Ratio::from_float(f64::NEG_INFINITY), None);
}
#[test]
fn test_signed() {
assert_eq!(_neg1_2.abs(), _1_2);
assert_eq!(_3_2.abs_sub(&_1_2), _1);
assert_eq!(_1_2.abs_sub(&_3_2), Zero::zero());
assert_eq!(_1_2.signum(), One::one());
assert_eq!(_neg1_2.signum(), - num::one::<Ratio<int>>());
assert!(_neg1_2.is_negative());
assert!(! _neg1_2.is_positive());
assert!(! _1_2.is_negative());
}
#[test]
fn test_hash() {
assert!(hash(&_0) != hash(&_1));
assert!(hash(&_0) != hash(&_3_2));
}
}

View File

@ -1,462 +0,0 @@
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Semantic version parsing and comparison.
//!
//! Semantic versioning (see http://semver.org/) is a set of rules for
//! assigning version numbers intended to convey meaning about what has
//! changed, and how much. A version number has five parts:
//!
//! * Major number, updated for incompatible API changes
//! * Minor number, updated for backwards-compatible API additions
//! * Patch number, updated for backwards-compatible bugfixes
//! * Pre-release information (optional), preceded by a hyphen (`-`)
//! * Build metadata (optional), preceded by a plus sign (`+`)
//!
//! The three mandatory components are required to be decimal numbers. The
//! pre-release information and build metadata are required to be a
//! period-separated list of identifiers containing only alphanumeric
//! characters and hyphens.
//!
//! An example version number with all five components is
//! `0.8.1-rc.3.0+20130922.linux`.
#![crate_name = "semver"]
#![deprecated = "This is now a cargo package located at: \
https://github.com/rust-lang/semver"]
#![allow(deprecated)]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
#![feature(default_type_params)]
use std::char;
use std::cmp;
use std::fmt::Show;
use std::fmt;
use std::hash;
/// An identifier in the pre-release or build metadata. If the identifier can
/// be parsed as a decimal value, it will be represented with `Numeric`.
#[deriving(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[allow(missing_doc)]
pub enum Identifier {
Numeric(uint),
AlphaNumeric(String)
}
impl fmt::Show for Identifier {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Numeric(ref n) => n.fmt(f),
AlphaNumeric(ref s) => s.fmt(f)
}
}
}
/// Represents a version number conforming to the semantic versioning scheme.
#[deriving(Clone, Eq)]
pub struct Version {
/// The major version, to be incremented on incompatible changes.
pub major: uint,
/// The minor version, to be incremented when functionality is added in a
/// backwards-compatible manner.
pub minor: uint,
/// The patch version, to be incremented when backwards-compatible bug
/// fixes are made.
pub patch: uint,
/// The pre-release version identifier, if one exists.
pub pre: Vec<Identifier>,
/// The build metadata, ignored when determining version precedence.
pub build: Vec<Identifier>,
}
impl fmt::Show for Version {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "{}.{}.{}", self.major, self.minor, self.patch))
if !self.pre.is_empty() {
try!(write!(f, "-"));
for (i, x) in self.pre.iter().enumerate() {
if i != 0 { try!(write!(f, ".")) };
try!(x.fmt(f));
}
}
if !self.build.is_empty() {
try!(write!(f, "+"));
for (i, x) in self.build.iter().enumerate() {
if i != 0 { try!(write!(f, ".")) };
try!(x.fmt(f));
}
}
Ok(())
}
}
impl cmp::PartialEq for Version {
#[inline]
fn eq(&self, other: &Version) -> bool {
// We should ignore build metadata here, otherwise versions v1 and v2
// can exist such that !(v1 < v2) && !(v1 > v2) && v1 != v2, which
// violate strict total ordering rules.
self.major == other.major &&
self.minor == other.minor &&
self.patch == other.patch &&
self.pre == other.pre
}
}
impl cmp::PartialOrd for Version {
fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl cmp::Ord for Version {
fn cmp(&self, other: &Version) -> Ordering {
match self.major.cmp(&other.major) {
Equal => {}
r => return r,
}
match self.minor.cmp(&other.minor) {
Equal => {}
r => return r,
}
match self.patch.cmp(&other.patch) {
Equal => {}
r => return r,
}
// NB: semver spec says 0.0.0-pre < 0.0.0
// but the version of ord defined for vec
// says that [] < [pre] so we alter it here
match (self.pre.len(), other.pre.len()) {
(0, 0) => Equal,
(0, _) => Greater,
(_, 0) => Less,
(_, _) => self.pre.cmp(&other.pre)
}
}
}
impl<S: hash::Writer> hash::Hash<S> for Version {
fn hash(&self, into: &mut S) {
self.major.hash(into);
self.minor.hash(into);
self.patch.hash(into);
self.pre.hash(into);
}
}
fn take_nonempty_prefix<T:Iterator<char>>(rdr: &mut T, pred: |char| -> bool)
-> (String, Option<char>) {
let mut buf = String::new();
let mut ch = rdr.next();
loop {
match ch {
None => break,
Some(c) if !pred(c) => break,
Some(c) => {
buf.push_char(c);
ch = rdr.next();
}
}
}
(buf, ch)
}
fn take_num<T: Iterator<char>>(rdr: &mut T) -> Option<(uint, Option<char>)> {
let (s, ch) = take_nonempty_prefix(rdr, char::is_digit);
match from_str::<uint>(s.as_slice()) {
None => None,
Some(i) => Some((i, ch))
}
}
fn take_ident<T: Iterator<char>>(rdr: &mut T) -> Option<(Identifier, Option<char>)> {
let (s,ch) = take_nonempty_prefix(rdr, char::is_alphanumeric);
if s.as_slice().chars().all(char::is_digit) {
match from_str::<uint>(s.as_slice()) {
None => None,
Some(i) => Some((Numeric(i), ch))
}
} else {
Some((AlphaNumeric(s), ch))
}
}
fn expect(ch: Option<char>, c: char) -> Option<()> {
if ch != Some(c) {
None
} else {
Some(())
}
}
fn parse_iter<T: Iterator<char>>(rdr: &mut T) -> Option<Version> {
let maybe_vers = take_num(rdr).and_then(|(major, ch)| {
expect(ch, '.').and_then(|_| Some(major))
}).and_then(|major| {
take_num(rdr).and_then(|(minor, ch)| {
expect(ch, '.').and_then(|_| Some((major, minor)))
})
}).and_then(|(major, minor)| {
take_num(rdr).and_then(|(patch, ch)| {
Some((major, minor, patch, ch))
})
});
let (major, minor, patch, ch) = match maybe_vers {
Some((a, b, c, d)) => (a, b, c, d),
None => return None
};
let mut pre = vec!();
let mut build = vec!();
let mut ch = ch;
if ch == Some('-') {
loop {
let (id, c) = match take_ident(rdr) {
Some((id, c)) => (id, c),
None => return None
};
pre.push(id);
ch = c;
if ch != Some('.') { break; }
}
}
if ch == Some('+') {
loop {
let (id, c) = match take_ident(rdr) {
Some((id, c)) => (id, c),
None => return None
};
build.push(id);
ch = c;
if ch != Some('.') { break; }
}
}
Some(Version {
major: major,
minor: minor,
patch: patch,
pre: pre,
build: build,
})
}
/// Parse a string into a semver object.
pub fn parse(s: &str) -> Option<Version> {
if !s.is_ascii() {
return None;
}
let s = s.trim();
let v = parse_iter(&mut s.chars());
match v {
Some(v) => {
if v.to_string().equiv(&s) {
Some(v)
} else {
None
}
}
None => None
}
}
#[test]
fn test_parse() {
assert_eq!(parse(""), None);
assert_eq!(parse(" "), None);
assert_eq!(parse("1"), None);
assert_eq!(parse("1.2"), None);
assert_eq!(parse("1.2"), None);
assert_eq!(parse("1"), None);
assert_eq!(parse("1.2"), None);
assert_eq!(parse("1.2.3-"), None);
assert_eq!(parse("a.b.c"), None);
assert_eq!(parse("1.2.3 abc"), None);
assert!(parse("1.2.3") == Some(Version {
major: 1u,
minor: 2u,
patch: 3u,
pre: vec!(),
build: vec!(),
}));
assert!(parse(" 1.2.3 ") == Some(Version {
major: 1u,
minor: 2u,
patch: 3u,
pre: vec!(),
build: vec!(),
}));
assert!(parse("1.2.3-alpha1") == Some(Version {
major: 1u,
minor: 2u,
patch: 3u,
pre: vec!(AlphaNumeric("alpha1".to_string())),
build: vec!(),
}));
assert!(parse(" 1.2.3-alpha1 ") == Some(Version {
major: 1u,
minor: 2u,
patch: 3u,
pre: vec!(AlphaNumeric("alpha1".to_string())),
build: vec!()
}));
assert!(parse("1.2.3+build5") == Some(Version {
major: 1u,
minor: 2u,
patch: 3u,
pre: vec!(),
build: vec!(AlphaNumeric("build5".to_string()))
}));
assert!(parse(" 1.2.3+build5 ") == Some(Version {
major: 1u,
minor: 2u,
patch: 3u,
pre: vec!(),
build: vec!(AlphaNumeric("build5".to_string()))
}));
assert!(parse("1.2.3-alpha1+build5") == Some(Version {
major: 1u,
minor: 2u,
patch: 3u,
pre: vec!(AlphaNumeric("alpha1".to_string())),
build: vec!(AlphaNumeric("build5".to_string()))
}));
assert!(parse(" 1.2.3-alpha1+build5 ") == Some(Version {
major: 1u,
minor: 2u,
patch: 3u,
pre: vec!(AlphaNumeric("alpha1".to_string())),
build: vec!(AlphaNumeric("build5".to_string()))
}));
assert!(parse("1.2.3-1.alpha1.9+build5.7.3aedf ") == Some(Version {
major: 1u,
minor: 2u,
patch: 3u,
pre: vec!(Numeric(1),AlphaNumeric("alpha1".to_string()),Numeric(9)),
build: vec!(AlphaNumeric("build5".to_string()),
Numeric(7),
AlphaNumeric("3aedf".to_string()))
}));
}
#[test]
fn test_eq() {
assert_eq!(parse("1.2.3"), parse("1.2.3"));
assert_eq!(parse("1.2.3-alpha1"), parse("1.2.3-alpha1"));
assert_eq!(parse("1.2.3+build.42"), parse("1.2.3+build.42"));
assert_eq!(parse("1.2.3-alpha1+42"), parse("1.2.3-alpha1+42"));
assert_eq!(parse("1.2.3+23"), parse("1.2.3+42"));
}
#[test]
fn test_ne() {
assert!(parse("0.0.0") != parse("0.0.1"));
assert!(parse("0.0.0") != parse("0.1.0"));
assert!(parse("0.0.0") != parse("1.0.0"));
assert!(parse("1.2.3-alpha") != parse("1.2.3-beta"));
}
#[test]
fn test_show() {
assert_eq!(format!("{}", parse("1.2.3").unwrap()),
"1.2.3".to_string());
assert_eq!(format!("{}", parse("1.2.3-alpha1").unwrap()),
"1.2.3-alpha1".to_string());
assert_eq!(format!("{}", parse("1.2.3+build.42").unwrap()),
"1.2.3+build.42".to_string());
assert_eq!(format!("{}", parse("1.2.3-alpha1+42").unwrap()),
"1.2.3-alpha1+42".to_string());
}
#[test]
fn test_to_string() {
assert_eq!(parse("1.2.3").unwrap().to_string(), "1.2.3".to_string());
assert_eq!(parse("1.2.3-alpha1").unwrap().to_string(), "1.2.3-alpha1".to_string());
assert_eq!(parse("1.2.3+build.42").unwrap().to_string(), "1.2.3+build.42".to_string());
assert_eq!(parse("1.2.3-alpha1+42").unwrap().to_string(), "1.2.3-alpha1+42".to_string());
}
#[test]
fn test_lt() {
assert!(parse("0.0.0") < parse("1.2.3-alpha2"));
assert!(parse("1.0.0") < parse("1.2.3-alpha2"));
assert!(parse("1.2.0") < parse("1.2.3-alpha2"));
assert!(parse("1.2.3-alpha1") < parse("1.2.3"));
assert!(parse("1.2.3-alpha1") < parse("1.2.3-alpha2"));
assert!(!(parse("1.2.3-alpha2") < parse("1.2.3-alpha2")));
assert!(!(parse("1.2.3+23") < parse("1.2.3+42")));
}
#[test]
fn test_le() {
assert!(parse("0.0.0") <= parse("1.2.3-alpha2"));
assert!(parse("1.0.0") <= parse("1.2.3-alpha2"));
assert!(parse("1.2.0") <= parse("1.2.3-alpha2"));
assert!(parse("1.2.3-alpha1") <= parse("1.2.3-alpha2"));
assert!(parse("1.2.3-alpha2") <= parse("1.2.3-alpha2"));
assert!(parse("1.2.3+23") <= parse("1.2.3+42"));
}
#[test]
fn test_gt() {
assert!(parse("1.2.3-alpha2") > parse("0.0.0"));
assert!(parse("1.2.3-alpha2") > parse("1.0.0"));
assert!(parse("1.2.3-alpha2") > parse("1.2.0"));
assert!(parse("1.2.3-alpha2") > parse("1.2.3-alpha1"));
assert!(parse("1.2.3") > parse("1.2.3-alpha2"));
assert!(!(parse("1.2.3-alpha2") > parse("1.2.3-alpha2")));
assert!(!(parse("1.2.3+23") > parse("1.2.3+42")));
}
#[test]
fn test_ge() {
assert!(parse("1.2.3-alpha2") >= parse("0.0.0"));
assert!(parse("1.2.3-alpha2") >= parse("1.0.0"));
assert!(parse("1.2.3-alpha2") >= parse("1.2.0"));
assert!(parse("1.2.3-alpha2") >= parse("1.2.3-alpha1"));
assert!(parse("1.2.3-alpha2") >= parse("1.2.3-alpha2"));
assert!(parse("1.2.3+23") >= parse("1.2.3+42"));
}
#[test]
fn test_spec_order() {
let vs = ["1.0.0-alpha",
"1.0.0-alpha.1",
"1.0.0-alpha.beta",
"1.0.0-beta",
"1.0.0-beta.2",
"1.0.0-beta.11",
"1.0.0-rc.1",
"1.0.0"];
let mut i = 1;
while i < vs.len() {
let a = parse(vs[i-1]).unwrap();
let b = parse(vs[i]).unwrap();
assert!(a < b);
i += 1;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,865 +0,0 @@
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/*!
Generate and parse UUIDs
Provides support for Universally Unique Identifiers (UUIDs). A UUID is a
unique 128-bit number, stored as 16 octets. UUIDs are used to assign unique
identifiers to entities without requiring a central allocating authority.
They are particularly useful in distributed systems, though can be used in
disparate areas, such as databases and network protocols. Typically a UUID is
displayed in a readable string form as a sequence of hexadecimal digits,
separated into groups by hyphens.
The uniqueness property is not strictly guaranteed, however for all practical
purposes, it can be assumed that an unintentional collision would be extremely
unlikely.
# Examples
To create a new random (V4) UUID and print it out in hexadecimal form:
```rust
# #![allow(deprecated)]
# extern crate uuid;
use uuid::Uuid;
fn main() {
let uuid1 = Uuid::new_v4();
println!("{}", uuid1.to_string());
}
```
# Strings
Examples of string representations:
* simple: `936DA01F9ABD4d9d80C702AF85C822A8`
* hyphenated: `550e8400-e29b-41d4-a716-446655440000`
* urn: `urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4`
# References
* [Wikipedia: Universally Unique Identifier](
http://en.wikipedia.org/wiki/Universally_unique_identifier)
* [RFC4122: A Universally Unique IDentifier (UUID) URN Namespace](
http://tools.ietf.org/html/rfc4122)
*/
#![crate_name = "uuid"]
#![deprecated = "This is now a cargo package located at: \
https://github.com/rust-lang/uuid"]
#![allow(deprecated)]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(default_type_params)]
// test harness access
#[cfg(test)]
extern crate test;
extern crate serialize;
use std::char::Char;
use std::default::Default;
use std::fmt;
use std::from_str::FromStr;
use std::hash;
use std::mem::{transmute,transmute_copy};
use std::num::FromStrRadix;
use std::rand;
use std::rand::Rng;
use std::slice;
use serialize::{Encoder, Encodable, Decoder, Decodable};
/// A 128-bit (16 byte) buffer containing the ID
pub type UuidBytes = [u8, ..16];
/// The version of the UUID, denoting the generating algorithm
#[deriving(PartialEq)]
pub enum UuidVersion {
/// Version 1: MAC address
Version1Mac = 1,
/// Version 2: DCE Security
Version2Dce = 2,
/// Version 3: MD5 hash
Version3Md5 = 3,
/// Version 4: Random
Version4Random = 4,
/// Version 5: SHA-1 hash
Version5Sha1 = 5,
}
/// The reserved variants of UUIDs
#[deriving(PartialEq)]
pub enum UuidVariant {
/// Reserved by the NCS for backward compatibility
VariantNCS,
/// As described in the RFC4122 Specification (default)
VariantRFC4122,
/// Reserved by Microsoft for backward compatibility
VariantMicrosoft,
/// Reserved for future expansion
VariantFuture,
}
/// A Universally Unique Identifier (UUID)
pub struct Uuid {
/// The 128-bit number stored in 16 bytes
bytes: UuidBytes
}
impl<S: hash::Writer> hash::Hash<S> for Uuid {
fn hash(&self, state: &mut S) {
self.bytes.hash(state)
}
}
/// A UUID stored as fields (identical to UUID, used only for conversions)
struct UuidFields {
/// First field, 32-bit word
data1: u32,
/// Second field, 16-bit short
data2: u16,
/// Third field, 16-bit short
data3: u16,
/// Fourth field, 8 bytes
data4: [u8, ..8]
}
/// Error details for string parsing failures
#[allow(missing_doc)]
pub enum ParseError {
ErrorInvalidLength(uint),
ErrorInvalidCharacter(char, uint),
ErrorInvalidGroups(uint),
ErrorInvalidGroupLength(uint, uint, uint),
}
/// Converts a ParseError to a string
impl fmt::Show for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ErrorInvalidLength(found) =>
write!(f, "Invalid length; expecting 32, 36 or 45 chars, \
found {}", found),
ErrorInvalidCharacter(found, pos) =>
write!(f, "Invalid character; found `{}` (0x{:02x}) at \
offset {}", found, found as uint, pos),
ErrorInvalidGroups(found) =>
write!(f, "Malformed; wrong number of groups: expected 1 \
or 5, found {}", found),
ErrorInvalidGroupLength(group, found, expecting) =>
write!(f, "Malformed; length of group {} was {}, \
expecting {}", group, found, expecting),
}
}
}
// Length of each hyphenated group in hex digits
#[allow(non_uppercase_statics)]
static UuidGroupLens: [uint, ..5] = [8u, 4u, 4u, 4u, 12u];
/// UUID support
impl Uuid {
/// Returns a nil or empty UUID (containing all zeroes)
pub fn nil() -> Uuid {
let uuid = Uuid{ bytes: [0, .. 16] };
uuid
}
/// Create a new UUID of the specified version
pub fn new(v: UuidVersion) -> Option<Uuid> {
match v {
Version4Random => Some(Uuid::new_v4()),
_ => None
}
}
/// Creates a new random UUID
///
/// Uses the `rand` module's default RNG task as the source
/// of random numbers. Use the rand::Rand trait to supply
/// a custom generator if required.
pub fn new_v4() -> Uuid {
let ub = rand::task_rng().gen_iter::<u8>().take(16).collect::<Vec<_>>();
let mut uuid = Uuid{ bytes: [0, .. 16] };
slice::bytes::copy_memory(uuid.bytes, ub.as_slice());
uuid.set_variant(VariantRFC4122);
uuid.set_version(Version4Random);
uuid
}
/// Creates a UUID using the supplied field values
///
/// # Arguments
/// * `d1` A 32-bit word
/// * `d2` A 16-bit word
/// * `d3` A 16-bit word
/// * `d4` Array of 8 octets
pub fn from_fields(d1: u32, d2: u16, d3: u16, d4: &[u8]) -> Uuid {
// First construct a temporary field-based struct
let mut fields = UuidFields {
data1: 0,
data2: 0,
data3: 0,
data4: [0, ..8]
};
fields.data1 = d1.to_be();
fields.data2 = d2.to_be();
fields.data3 = d3.to_be();
slice::bytes::copy_memory(fields.data4, d4);
unsafe {
transmute(fields)
}
}
/// Creates a UUID using the supplied bytes
///
/// # Arguments
/// * `b` An array or slice of 16 bytes
pub fn from_bytes(b: &[u8]) -> Option<Uuid> {
if b.len() != 16 {
return None
}
let mut uuid = Uuid{ bytes: [0, .. 16] };
slice::bytes::copy_memory(uuid.bytes, b);
Some(uuid)
}
/// Specifies the variant of the UUID structure
fn set_variant(&mut self, v: UuidVariant) {
// Octet 8 contains the variant in the most significant 3 bits
match v {
VariantNCS => // b0xx...
self.bytes[8] = self.bytes[8] & 0x7f,
VariantRFC4122 => // b10x...
self.bytes[8] = (self.bytes[8] & 0x3f) | 0x80,
VariantMicrosoft => // b110...
self.bytes[8] = (self.bytes[8] & 0x1f) | 0xc0,
VariantFuture => // b111...
self.bytes[8] = (self.bytes[8] & 0x1f) | 0xe0,
}
}
/// Returns the variant of the UUID structure
///
/// This determines the interpretation of the structure of the UUID.
/// Currently only the RFC4122 variant is generated by this module.
///
/// * [Variant Reference](http://tools.ietf.org/html/rfc4122#section-4.1.1)
pub fn get_variant(&self) -> Option<UuidVariant> {
if self.bytes[8] & 0x80 == 0x00 {
Some(VariantNCS)
} else if self.bytes[8] & 0xc0 == 0x80 {
Some(VariantRFC4122)
} else if self.bytes[8] & 0xe0 == 0xc0 {
Some(VariantMicrosoft)
} else if self.bytes[8] & 0xe0 == 0xe0 {
Some(VariantFuture)
} else {
None
}
}
/// Specifies the version number of the UUID
fn set_version(&mut self, v: UuidVersion) {
self.bytes[6] = (self.bytes[6] & 0xF) | ((v as u8) << 4);
}
/// Returns the version number of the UUID
///
/// This represents the algorithm used to generate the contents.
///
/// Currently only the Random (V4) algorithm is supported by this
/// module. There are security and privacy implications for using
/// older versions - see [Wikipedia: Universally Unique Identifier](
/// http://en.wikipedia.org/wiki/Universally_unique_identifier) for
/// details.
///
/// * [Version Reference](http://tools.ietf.org/html/rfc4122#section-4.1.3)
pub fn get_version_num(&self) -> uint {
(self.bytes[6] >> 4) as uint
}
/// Returns the version of the UUID
///
/// This represents the algorithm used to generate the contents
pub fn get_version(&self) -> Option<UuidVersion> {
let v = self.bytes[6] >> 4;
match v {
1 => Some(Version1Mac),
2 => Some(Version2Dce),
3 => Some(Version3Md5),
4 => Some(Version4Random),
5 => Some(Version5Sha1),
_ => None
}
}
/// Return an array of 16 octets containing the UUID data
pub fn as_bytes(&self) -> &[u8] {
self.bytes.as_slice()
}
/// Returns the UUID as a string of 16 hexadecimal digits
///
/// Example: `936DA01F9ABD4d9d80C702AF85C822A8`
pub fn to_simple_str(&self) -> String {
let mut s: Vec<u8> = Vec::from_elem(32, 0u8);
for i in range(0u, 16u) {
let digit = format!("{:02x}", self.bytes[i] as uint);
*s.get_mut(i*2+0) = digit.as_bytes()[0];
*s.get_mut(i*2+1) = digit.as_bytes()[1];
}
String::from_utf8(s).unwrap()
}
/// Returns a string of hexadecimal digits, separated into groups with a hyphen.
///
/// Example: `550e8400-e29b-41d4-a716-446655440000`
pub fn to_hyphenated_str(&self) -> String {
// Convert to field-based struct as it matches groups in output.
// Ensure fields are in network byte order, as per RFC.
let mut uf: UuidFields;
unsafe {
uf = transmute_copy(&self.bytes);
}
uf.data1 = uf.data1.to_be();
uf.data2 = uf.data2.to_be();
uf.data3 = uf.data3.to_be();
let s = format!("{:08x}-{:04x}-{:04x}-{:02x}{:02x}-\
{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
uf.data1,
uf.data2, uf.data3,
uf.data4[0], uf.data4[1],
uf.data4[2], uf.data4[3], uf.data4[4],
uf.data4[5], uf.data4[6], uf.data4[7]);
s
}
/// Returns the UUID formatted as a full URN string
///
/// This is the same as the hyphenated format, but with the "urn:uuid:" prefix.
///
/// Example: `urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4`
pub fn to_urn_str(&self) -> String {
format!("urn:uuid:{}", self.to_hyphenated_str())
}
/// Parses a UUID from a string of hexadecimal digits with optional hyphens
///
/// Any of the formats generated by this module (simple, hyphenated, urn) are
/// supported by this parsing function.
pub fn parse_string(us: &str) -> Result<Uuid, ParseError> {
let mut us = us.clone();
let orig_len = us.len();
// Ensure length is valid for any of the supported formats
if orig_len != 32 && orig_len != 36 && orig_len != 45 {
return Err(ErrorInvalidLength(orig_len));
}
// Strip off URN prefix if present
if us.starts_with("urn:uuid:") {
us = us.slice(9, orig_len);
}
// Make sure all chars are either hex digits or hyphen
for (i, c) in us.chars().enumerate() {
match c {
'0'...'9' | 'A'...'F' | 'a'...'f' | '-' => {},
_ => return Err(ErrorInvalidCharacter(c, i)),
}
}
// Split string up by hyphens into groups
let hex_groups: Vec<&str> = us.split_str("-").collect();
// Get the length of each group
let group_lens: Vec<uint> = hex_groups.iter().map(|&v| v.len()).collect();
// Ensure the group lengths are valid
match group_lens.len() {
// Single group, no hyphens
1 => {
if group_lens[0] != 32 {
return Err(ErrorInvalidLength(group_lens[0]));
}
},
// Five groups, hyphens in between each
5 => {
// Ensure each group length matches the expected
for (i, (&gl, &expected)) in
group_lens.iter().zip(UuidGroupLens.iter()).enumerate() {
if gl != expected {
return Err(ErrorInvalidGroupLength(i, gl, expected))
}
}
},
_ => {
return Err(ErrorInvalidGroups(group_lens.len()));
}
}
// Normalise into one long hex string
let vs = hex_groups.concat();
// At this point, we know we have a valid hex string, without hyphens
assert!(vs.len() == 32);
assert!(vs.as_slice().chars().all(|c| c.is_digit_radix(16)));
// Allocate output UUID buffer
let mut ub = [0u8, ..16];
// Extract each hex digit from the string
for i in range(0u, 16u) {
ub[i] = FromStrRadix::from_str_radix(vs.as_slice()
.slice(i*2, (i+1)*2),
16).unwrap();
}
Ok(Uuid::from_bytes(ub).unwrap())
}
/// Tests if the UUID is nil
pub fn is_nil(&self) -> bool {
return self.bytes.iter().all(|&b| b == 0);
}
}
impl Default for Uuid {
/// Returns the nil UUID, which is all zeroes
fn default() -> Uuid {
Uuid::nil()
}
}
impl Clone for Uuid {
/// Returns a copy of the UUID
fn clone(&self) -> Uuid { *self }
}
impl FromStr for Uuid {
/// Parse a hex string and interpret as a UUID
///
/// Accepted formats are a sequence of 32 hexadecimal characters,
/// with or without hyphens (grouped as 8, 4, 4, 4, 12).
fn from_str(us: &str) -> Option<Uuid> {
let result = Uuid::parse_string(us);
match result {
Ok(u) => Some(u),
Err(_) => None
}
}
}
/// Convert the UUID to a hexadecimal-based string representation
impl fmt::Show for Uuid {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.to_simple_str())
}
}
/// Test two UUIDs for equality
///
/// UUIDs are equal only when they are byte-for-byte identical
impl PartialEq for Uuid {
fn eq(&self, other: &Uuid) -> bool {
self.bytes == other.bytes
}
}
impl Eq for Uuid {}
// FIXME #9845: Test these more thoroughly
impl<T: Encoder<E>, E> Encodable<T, E> for Uuid {
/// Encode a UUID as a hyphenated string
fn encode(&self, e: &mut T) -> Result<(), E> {
e.emit_str(self.to_hyphenated_str().as_slice())
}
}
impl<T: Decoder<E>, E> Decodable<T, E> for Uuid {
/// Decode a UUID from a string
fn decode(d: &mut T) -> Result<Uuid, E> {
match from_str(try!(d.read_str()).as_slice()) {
Some(decode) => Ok(decode),
None => Err(d.error("Unable to decode UUID"))
}
}
}
/// Generates a random instance of UUID (V4 conformant)
impl rand::Rand for Uuid {
#[inline]
fn rand<R: rand::Rng>(rng: &mut R) -> Uuid {
let ub = rng.gen_iter::<u8>().take(16).collect::<Vec<_>>();
let mut uuid = Uuid{ bytes: [0, .. 16] };
slice::bytes::copy_memory(uuid.bytes, ub.as_slice());
uuid.set_variant(VariantRFC4122);
uuid.set_version(Version4Random);
uuid
}
}
#[cfg(test)]
mod uuidtest {
use super::{Uuid, VariantMicrosoft, VariantNCS, VariantRFC4122,
Version1Mac, Version2Dce, Version3Md5, Version4Random,
Version5Sha1};
use std::rand;
#[test]
fn test_nil() {
let nil = Uuid::nil();
let not_nil = Uuid::new_v4();
assert!(nil.is_nil());
assert!(!not_nil.is_nil());
}
#[test]
fn test_new() {
// Supported
let uuid1 = Uuid::new(Version4Random).unwrap();
let s = uuid1.to_simple_str();
assert!(s.len() == 32);
assert!(uuid1.get_version().unwrap() == Version4Random);
// Test unsupported versions
assert!(Uuid::new(Version1Mac) == None);
assert!(Uuid::new(Version2Dce) == None);
assert!(Uuid::new(Version3Md5) == None);
assert!(Uuid::new(Version5Sha1) == None);
}
#[test]
fn test_new_v4() {
let uuid1 = Uuid::new_v4();
assert!(uuid1.get_version().unwrap() == Version4Random);
assert!(uuid1.get_variant().unwrap() == VariantRFC4122);
}
#[test]
fn test_get_version() {
let uuid1 = Uuid::new_v4();
assert!(uuid1.get_version().unwrap() == Version4Random);
assert!(uuid1.get_version_num() == 4);
}
#[test]
fn test_get_variant() {
let uuid1 = Uuid::new_v4();
let uuid2 = Uuid::parse_string("550e8400-e29b-41d4-a716-446655440000").unwrap();
let uuid3 = Uuid::parse_string("67e55044-10b1-426f-9247-bb680e5fe0c8").unwrap();
let uuid4 = Uuid::parse_string("936DA01F9ABD4d9dC0C702AF85C822A8").unwrap();
let uuid5 = Uuid::parse_string("F9168C5E-CEB2-4faa-D6BF-329BF39FA1E4").unwrap();
let uuid6 = Uuid::parse_string("f81d4fae-7dec-11d0-7765-00a0c91e6bf6").unwrap();
assert!(uuid1.get_variant().unwrap() == VariantRFC4122);
assert!(uuid2.get_variant().unwrap() == VariantRFC4122);
assert!(uuid3.get_variant().unwrap() == VariantRFC4122);
assert!(uuid4.get_variant().unwrap() == VariantMicrosoft);
assert!(uuid5.get_variant().unwrap() == VariantMicrosoft);
assert!(uuid6.get_variant().unwrap() == VariantNCS);
}
#[test]
fn test_parse_uuid_v4() {
use super::{ErrorInvalidCharacter, ErrorInvalidGroups,
ErrorInvalidGroupLength, ErrorInvalidLength};
// Invalid
assert!(Uuid::parse_string("").is_err());
assert!(Uuid::parse_string("!").is_err());
assert!(Uuid::parse_string("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E45").is_err());
assert!(Uuid::parse_string("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4").is_err());
assert!(Uuid::parse_string("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4").is_err());
assert!(Uuid::parse_string("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4").is_err());
assert!(Uuid::parse_string("F9168C5E-CEB2-4faa").is_err());
assert!(Uuid::parse_string("F9168C5E-CEB2-4faaXB6BFF329BF39FA1E4").is_err());
assert!(Uuid::parse_string("F9168C5E-CEB-24fa-eB6BFF32-BF39FA1E4").is_err());
assert!(Uuid::parse_string("01020304-1112-2122-3132-41424344").is_err());
assert!(Uuid::parse_string("67e5504410b1426f9247bb680e5fe0c").is_err());
assert!(Uuid::parse_string("67e5504410b1426f9247bb680e5fe0c88").is_err());
assert!(Uuid::parse_string("67e5504410b1426f9247bb680e5fe0cg8").is_err());
assert!(Uuid::parse_string("67e5504410b1426%9247bb680e5fe0c8").is_err());
// Valid
assert!(Uuid::parse_string("00000000000000000000000000000000").is_ok());
assert!(Uuid::parse_string("67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
assert!(Uuid::parse_string("67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
assert!(Uuid::parse_string("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").is_ok());
assert!(Uuid::parse_string("67e5504410b1426f9247bb680e5fe0c8").is_ok());
assert!(Uuid::parse_string("01020304-1112-2122-3132-414243444546").is_ok());
assert!(Uuid::parse_string("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
// Nil
let nil = Uuid::nil();
assert!(Uuid::parse_string("00000000000000000000000000000000").unwrap() == nil);
assert!(Uuid::parse_string("00000000-0000-0000-0000-000000000000").unwrap() == nil);
// Round-trip
let uuid_orig = Uuid::new_v4();
let orig_str = uuid_orig.to_string();
let uuid_out = Uuid::parse_string(orig_str.as_slice()).unwrap();
assert!(uuid_orig == uuid_out);
// Test error reporting
let e = Uuid::parse_string("67e5504410b1426f9247bb680e5fe0c").unwrap_err();
assert!(match e { ErrorInvalidLength(n) => n==31, _ => false });
let e = Uuid::parse_string("67e550X410b1426f9247bb680e5fe0cd").unwrap_err();
assert!(match e { ErrorInvalidCharacter(c, n) => c=='X' && n==6, _ => false });
let e = Uuid::parse_string("67e550-4105b1426f9247bb680e5fe0c").unwrap_err();
assert!(match e { ErrorInvalidGroups(n) => n==2, _ => false });
let e = Uuid::parse_string("F9168C5E-CEB2-4faa-B6BF1-02BF39FA1E4").unwrap_err();
assert!(match e { ErrorInvalidGroupLength(g, n, e) => g==3 && n==5 && e==4, _ => false });
}
#[test]
fn test_to_simple_str() {
let uuid1 = Uuid::new_v4();
let s = uuid1.to_simple_str();
assert!(s.len() == 32);
assert!(s.as_slice().chars().all(|c| c.is_digit_radix(16)));
}
#[test]
fn test_to_string() {
let uuid1 = Uuid::new_v4();
let s = uuid1.to_string();
assert!(s.len() == 32);
assert!(s.as_slice().chars().all(|c| c.is_digit_radix(16)));
}
#[test]
fn test_to_hyphenated_str() {
let uuid1 = Uuid::new_v4();
let s = uuid1.to_hyphenated_str();
assert!(s.len() == 36);
assert!(s.as_slice().chars().all(|c| c.is_digit_radix(16) || c == '-'));
}
#[test]
fn test_to_urn_str() {
let uuid1 = Uuid::new_v4();
let ss = uuid1.to_urn_str();
let s = ss.as_slice().slice(9, ss.len());
assert!(ss.as_slice().starts_with("urn:uuid:"));
assert!(s.len() == 36);
assert!(s.as_slice()
.chars()
.all(|c| c.is_digit_radix(16) || c == '-'));
}
#[test]
fn test_to_str_matching() {
let uuid1 = Uuid::new_v4();
let hs = uuid1.to_hyphenated_str();
let ss = uuid1.to_string();
let hsn = String::from_chars(hs.as_slice()
.chars()
.filter(|&c| c != '-')
.collect::<Vec<char>>()
.as_slice());
assert!(hsn == ss);
}
#[test]
fn test_string_roundtrip() {
let uuid = Uuid::new_v4();
let hs = uuid.to_hyphenated_str();
let uuid_hs = Uuid::parse_string(hs.as_slice()).unwrap();
assert!(uuid_hs == uuid);
let ss = uuid.to_string();
let uuid_ss = Uuid::parse_string(ss.as_slice()).unwrap();
assert!(uuid_ss == uuid);
}
#[test]
fn test_compare() {
let uuid1 = Uuid::new_v4();
let uuid2 = Uuid::new_v4();
assert!(uuid1 == uuid1);
assert!(uuid2 == uuid2);
assert!(uuid1 != uuid2);
assert!(uuid2 != uuid1);
}
#[test]
fn test_from_fields() {
let d1: u32 = 0xa1a2a3a4;
let d2: u16 = 0xb1b2;
let d3: u16 = 0xc1c2;
let d4: Vec<u8> = vec!(0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8);
let u = Uuid::from_fields(d1, d2, d3, d4.as_slice());
let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8".to_string();
let result = u.to_simple_str();
assert!(result == expected);
}
#[test]
fn test_from_bytes() {
let b = vec!( 0xa1, 0xa2, 0xa3, 0xa4, 0xb1, 0xb2, 0xc1, 0xc2,
0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8 );
let u = Uuid::from_bytes(b.as_slice()).unwrap();
let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8".to_string();
assert!(u.to_simple_str() == expected);
}
#[test]
fn test_as_bytes() {
let u = Uuid::new_v4();
let ub = u.as_bytes();
assert!(ub.len() == 16);
assert!(! ub.iter().all(|&b| b == 0));
}
#[test]
fn test_bytes_roundtrip() {
let b_in: [u8, ..16] = [ 0xa1, 0xa2, 0xa3, 0xa4, 0xb1, 0xb2, 0xc1, 0xc2,
0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8 ];
let u = Uuid::from_bytes(b_in.clone()).unwrap();
let b_out = u.as_bytes();
assert!(b_in == b_out);
}
#[test]
fn test_operator_eq() {
let u1 = Uuid::new_v4();
let u2 = u1.clone();
let u3 = Uuid::new_v4();
assert!(u1 == u1);
assert!(u1 == u2);
assert!(u2 == u1);
assert!(u1 != u3);
assert!(u3 != u1);
assert!(u2 != u3);
assert!(u3 != u2);
}
#[test]
fn test_rand_rand() {
let mut rng = rand::task_rng();
let u: Uuid = rand::Rand::rand(&mut rng);
let ub = u.as_bytes();
assert!(ub.len() == 16);
assert!(! ub.iter().all(|&b| b == 0));
}
#[test]
fn test_serialize_round_trip() {
use serialize::json;
let u = Uuid::new_v4();
let s = json::encode(&u);
let u2 = json::decode(s.as_slice()).unwrap();
assert_eq!(u, u2);
}
#[test]
fn test_bad_decode() {
use serialize::json;
use serialize::{Decodable};
let js_good = json::String("a1a2a3a4a5a6a7a8a1a2a3a4a5a6a7a8".to_string());
let js_bad1 = json::String("a1a2a3a4a5a6a7a8a1a2a3a4a5a6a7ah".to_string());
let js_bad2 = json::String("a1a2a3a4a5a6a7a8a1a2a3a4a5a6a7a".to_string());
let u_good: Result<Uuid, _> = Decodable::decode(&mut json::Decoder::new(js_good));
let u_bad1: Result<Uuid, _> = Decodable::decode(&mut json::Decoder::new(js_bad1));
let u_bad2: Result<Uuid, _> = Decodable::decode(&mut json::Decoder::new(js_bad2));
assert!(u_good.is_ok());
assert!(u_bad1.is_err());
assert!(u_bad2.is_err());
}
#[test]
fn test_iterbytes_impl_for_uuid() {
use std::collections::HashSet;
let mut set = HashSet::new();
let id1 = Uuid::new_v4();
let id2 = Uuid::new_v4();
set.insert(id1);
assert!(set.contains(&id1));
assert!(!set.contains(&id2));
}
}
#[cfg(test)]
mod bench {
extern crate test;
use self::test::Bencher;
use super::Uuid;
#[bench]
pub fn create_uuids(b: &mut Bencher) {
b.iter(|| {
Uuid::new_v4();
})
}
#[bench]
pub fn uuid_to_string(b: &mut Bencher) {
let u = Uuid::new_v4();
b.iter(|| {
u.to_string();
})
}
#[bench]
pub fn parse_str(b: &mut Bencher) {
let s = "urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4";
b.iter(|| {
Uuid::parse_string(s).unwrap();
})
}
}