├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Cargo.toml ├── README.md ├── build.rs ├── examples ├── bitflags.rs ├── byteorder.rs ├── chrono.rs ├── clap.rs ├── encoding_rs.rs ├── error-chain.rs ├── flate2.rs ├── fnv.rs ├── itertools.rs ├── lazy_static.rs ├── libc.rs ├── log.rs ├── memmap.rs ├── ndarray.rs ├── num.rs ├── num_cpus.rs ├── rand.rs ├── rayon.rs ├── regex.rs ├── reqwest.rs ├── semver.rs ├── serde.rs ├── serde_json.rs ├── tar.rs ├── tempdir.rs ├── threadpool.rs ├── toml.rs ├── url.rs └── walkdir.rs ├── src └── lib.rs └── tests └── skeptic.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | *~ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | 3 | script: 4 | - cargo build 5 | - cargo test 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.119.0-rc 2 | 3 | - [Added num_cpus and threadpool](https://github.com/brson/stdx/pull/41) 4 | - [Add walkdir](https://github.com/brson/stdx/pull/43) 5 | - [Add itertools](https://github.com/brson/stdx/pull/40) 6 | - [Add fnv](https://github.com/brson/stdx/pull/38) 7 | - [Upgrade to chrono 0.4.0](https://github.com/brson/stdx/pull/47) 8 | - [Add various polish](https://github.com/brson/stdx/pull/49) 9 | - [Fix broken link to error handling in rust docs](https://github.com/brson/stdx/pull/52) 10 | - [Add cargo build / test to travis](https://github.com/brson/stdx/pull/56) 11 | - [Bump all deps for 1.19](https://github.com/brson/stdx/pull/57) 12 | - [Test with skeptic](https://github.com/brson/stdx/pull/58) 13 | 14 | Contributors: Alisha, Anna Liao, Brian Anderson, David Peklak, dowon 15 | Cha, Isaac Grosof, plafü, Tshepang Lekhonkhobe 16 | 17 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to stdx 2 | 3 | As a contributor to stdx, the main thing to be aware of when adding or 4 | modifying examples is the conventions around how the examples are 5 | organized. There are a number of elements that need to be kept in 6 | sync. 7 | 8 | The main product of stdx is its README.md file, which contains an 9 | index of crates, their examples, links to their documentation, and 10 | links to the example as a source file. The Cargo.toml file must be 11 | maintained as well. 12 | 13 | Crates in stdx are categorized as 14 | 15 | - _primary_ - these are the crates of stdx. They are represented in 16 | the Cargo.toml file and the index. 17 | - _supplemental_ - these are crates users are likely to want to use with 18 | a stdx crate. They are listed in the crate description as 19 | "supplemental", and may or may not be part of index. They are 20 | included of the Cargo.toml file. 21 | - _alternatives_ - These are not part of stdx but are notable 22 | alternatives that fulfill the same functions as crates in stdx. 23 | 24 | Everywhere crates appear they are listed in alphabetical order. This 25 | includes Cargo.toml, the index, and the link definitions in the 26 | markdown. 27 | 28 | Crates are often described in the form `cratename = "version"`. This 29 | is so it can be directly copied into the user's Cargo.toml. But it 30 | results in a bunch of duplication for stdx maintenance. 31 | 32 | The bits that need to be maintained are: 33 | 34 | - The version numbers in Cargo.toml 35 | - The version numbers in the index 36 | - The version numbers in index in README.md 37 | - The version numbers in the crate headers in README.md 38 | - The version numbers in the link definitions at the end of README.md 39 | 40 | All links are defined at the end of README.md 41 | 42 | Every crate has an example, and that example is duplicated in both 43 | README.md and in the `examples/` folder. So when updating an example 44 | make sure to do it in both places. 45 | 46 | Test with `cargo test`, which will both build the examples in 47 | the `examples` folder, and run the examples in README.md. 48 | 49 | Each crate in the README is accompanied with a short description. This 50 | description should tell a little story about Rust. When is this crate needed? 51 | Is there anything Rust-specific about this crate that would provide interesting 52 | context? Is there any background reading to link to that would educate an 53 | inexperienced reader? Does this crate have an interesting history? If the 54 | description mentions Rust types that the reader may not be aware of remember to 55 | hyperlink them. 56 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stdx" 3 | version = "0.119.0-rc" 4 | authors = ["Brian Anderson "] 5 | description = "The missing batteries of Rust" 6 | license = "MIT/Apache-2.0" 7 | 8 | [dependencies] 9 | 10 | # If you update these also update all the versions in README.md 11 | # Note: crates are presented in alphabetical order. 12 | 13 | bitflags = "0.9.1" 14 | byteorder = "1.1.0" 15 | chrono = { version = "0.4.0", features = ["serde"] } 16 | clap = "2.25.0" 17 | encoding_rs = "0.6.11" 18 | error-chain = "0.10.0" 19 | flate2 = "0.2.19" 20 | fnv = "1.0.5" 21 | itertools = "0.6.0" 22 | lazy_static = "0.2.8" 23 | libc = "0.2.26" 24 | log = "0.3.8" 25 | memmap = "0.5.2" 26 | # FIXME bluss/rust-ndarray#314 serde 27 | ndarray = "0.9.1" 28 | num = "0.1.40" 29 | num_cpus = "1.6.2" 30 | rand = "0.3.15" 31 | rayon = "0.8.2" 32 | regex = "0.2.2" 33 | reqwest = { version = "0.7.1" } 34 | semver = { version = "0.7.0", features = ["serde"] } 35 | serde = "1.0.10" 36 | serde_json = "1.0.2" 37 | tar = "0.4.13" 38 | tempdir = "0.3.5" 39 | threadpool = "1.4.0" 40 | toml = "0.4.5" 41 | url = "1.5.1" 42 | walkdir = "1.0.7" 43 | 44 | # Supplemental dependencies 45 | env_logger = "0.4.3" 46 | serde_derive = "1.0.10" 47 | 48 | [build-dependencies] 49 | skeptic = "0.13.4" 50 | 51 | [dev-dependencies] 52 | skeptic = "0.13.4" 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **This project is unmaintained. For a similar project see [rustmax](https://github.com/brson/rustmax).** 2 | 3 | 4 | # `stdx` - The missing batteries of Rust 5 | 6 | New to Rust and don't yet know what crates to use? 7 | [**stdx has the best crates**](#about-stdx). 8 | 9 | Current revision: `stdx` 0.119.0-rc, for Rust 1.19, July 20, 2017. 10 | 11 | | Feature | Crate | | 12 | |--------------------------------|----------------------------|--------------------| 13 | | Bitfields | [`bitflags = "0.9.1"`] | [📖][d-bitflags] | 14 | | Byte order conversion | [`byteorder = "1.1.0"`] | [📖][d-byteorder] | 15 | | Date and time | [`chrono = "0.4.0"`] | [📖][d-chrono] | 16 | | Command-line argument parsing | [`clap = "2.25.0"`] | [📖][d-clap] | 17 | | Encoding/decoding | [`encoding_rs = "0.6.11"`] | [📖][d-encoding_rs] | 18 | | Error handling | [`error-chain = "0.10.0"`] | [📖][d-error-chain] | 19 | | Fast hashing | [`fnv = "1.0.5"`] | [📖][d-fnv] | 20 | | Compression - deflate (gzip) | [`flate2 = "0.2.19"`] | [📖][d-flate2] | 21 | | Iterator functions, macros | [`itertools = "0.6.0"`] | [📖][d-itertools] | 22 | | Global initialization | [`lazy_static = "0.2.8"`] | [📖][d-lazy_static] | 23 | | C interop | [`libc = "0.2.25"`] | [📖][d-libc] | 24 | | Logging | [`log = "0.3.8"`] | [📖][d-log] | 25 | | Memory-mapped file I/O | [`memmap = "0.5.2"`] | [📖][d-memmap] | 26 | | Multidimensional arrays | [`ndarray = "0.9.1"`] | [📖][d-ndarray] | 27 | | Big, rational, complex numbers | [`num = "0.1.40"`] | [📖][d-num] | 28 | | Number of CPUs | [`num_cpus = "1.6.2"`] | [📖][d-num_cpus] | 29 | | Random numbers | [`rand = "0.3.15"`] | [📖][d-rand] | 30 | | Parallel iteration | [`rayon = "0.8.2"`] | [📖][d-rayon] | 31 | | Regular expressions | [`regex = "0.2.2"`] | [📖][d-regex] | 32 | | HTTP client | [`reqwest = "0.7.1"`] | [📖][d-reqwest] | 33 | | Software versioning | [`semver = "0.7.0"`] | [📖][d-semver] | 34 | | Serialization | [`serde = "1.0.10"`] | [📖][d-serde] | 35 | | JSON | [`serde_json = "1.0.2"`] | [📖][d-serde_json] | 36 | | Tar archives | [`tar = "0.4.23"`] | [📖][d-tar] | 37 | | Temporary directories | [`tempdir = "0.3.5"`] | [📖][d-tempdir] | 38 | | Thread pool | [`threadpool = "1.4.0"`] | [📖][d-threadpool] | 39 | | Configuration files | [`toml = "0.4.2"`] | [📖][d-toml] | 40 | | URLs | [`url = "1.5.1"`] | [📖][d-url] | 41 | | Directory traversal | [`walkdir = "1.0.7"`] | [📖][d-walkdir] | 42 | 43 |       44 | 45 | 46 | 47 | ### `bitflags = "0.9.1"`   [📖][d-bitflags] 48 | 49 | The only thing this crate does is export the [`bitflags!`] macro, but 50 | it's a heckuva-useful macro. `bitflags!` produces typesafe bitmasks, 51 | types with named values that are efficiently packed together as bits 52 | to express sets of options. 53 | 54 | **Example**: [`examples/bitflags.rs`] 55 | 56 | ```rust 57 | #[macro_use] 58 | extern crate bitflags; 59 | 60 | bitflags! { 61 | struct Flags: u32 { 62 | const FLAG_A = 0b00000001; 63 | const FLAG_B = 0b00000010; 64 | const FLAG_C = 0b00000100; 65 | const FLAG_ABC = FLAG_A.bits 66 | | FLAG_B.bits 67 | | FLAG_C.bits; 68 | } 69 | } 70 | 71 | fn main() { 72 | let e1 = FLAG_A | FLAG_C; 73 | let e2 = FLAG_B | FLAG_C; 74 | assert_eq!((e1 | e2), FLAG_ABC); // union 75 | assert_eq!((e1 & e2), FLAG_C); // intersection 76 | assert_eq!((e1 - e2), FLAG_A); // set difference 77 | assert_eq!(!e2, FLAG_A); // set complement 78 | } 79 | ``` 80 | 81 |       82 | 83 | 84 | 85 | ### `byteorder = "1.1.0"`   [📖][d-byteorder] 86 | 87 | When serializing integers it's important to consider that not all 88 | computers store in memory the individual bytes of the number in the 89 | same order. The choice of byte order is called ["endianness"], and 90 | this simple crate provides the crucial functions for converting 91 | between numbers and bytes, in little-endian, or big-endian orders. 92 | 93 | **Example**: [`examples/byteorder.rs`] 94 | 95 | ```rust 96 | extern crate byteorder; 97 | 98 | use std::io::Cursor; 99 | use byteorder::{BigEndian, ReadBytesExt}; 100 | use byteorder::{LittleEndian, WriteBytesExt}; 101 | 102 | fn main() { 103 | // Read unsigned 16 bit big-endian integers from a Read type: 104 | let mut rdr = Cursor::new(vec![2, 5, 3, 0]); 105 | // Note that we use type parameters to indicate which kind of byte 106 | // order we want! 107 | assert_eq!(517, rdr.read_u16::().unwrap()); 108 | assert_eq!(768, rdr.read_u16::().unwrap()); 109 | 110 | // Write unsigned 16 bit little-endian integers to a Write type: 111 | let mut wtr = vec![]; 112 | wtr.write_u16::(517).unwrap(); 113 | wtr.write_u16::(768).unwrap(); 114 | assert_eq!(wtr, vec![5, 2, 0, 3]); 115 | } 116 | ``` 117 | 118 |       119 | 120 | 121 | 122 | ### `chrono = "0.4.0"`   [📖][d-chrono] 123 | 124 | Date and time types. 125 | 126 | **Example**: [`examples/chrono.rs`] 127 | 128 | ```rust 129 | extern crate chrono; 130 | use chrono::*; 131 | 132 | fn main() { 133 | let local: DateTime = Local::now(); 134 | let utc: DateTime = Utc::now(); 135 | 136 | let dt = Utc.ymd(2014, 11, 28).and_hms(12, 0, 9); 137 | 138 | assert_eq!((dt.year(), dt.month(), dt.day()), (2014, 11, 28)); 139 | assert_eq!((dt.hour(), dt.minute(), dt.second()), (12, 0, 9)); 140 | 141 | assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2014-11-28 12:00:09"); 142 | assert_eq!(dt.format("%a %b %e %T %Y").to_string(), "Fri Nov 28 12:00:09 2014"); 143 | 144 | assert_eq!(format!("{}", dt), "2014-11-28 12:00:09 UTC"); 145 | } 146 | ``` 147 | 148 |       149 | 150 | 151 | 152 | ### `clap = "2.25.0"`   [📖][d-clap] 153 | 154 | Clap is a command line argument parser that is easy to 155 | use and is highly configurable. 156 | 157 | **Example**: [`examples/clap.rs`] 158 | 159 | ```rust,no_run 160 | extern crate clap; 161 | use clap::{Arg, App, SubCommand}; 162 | 163 | fn main() { 164 | let app = App::new("My Super Program") 165 | .version("1.0") 166 | .author("Kevin K. ") 167 | .about("Does awesome things") 168 | .arg(Arg::with_name("config") 169 | .short("c") 170 | .long("config") 171 | .value_name("FILE") 172 | .help("Sets a custom config file") 173 | .takes_value(true)) 174 | .arg(Arg::with_name("INPUT") 175 | .help("Sets the input file to use") 176 | .required(true) 177 | .index(1)) 178 | .subcommand(SubCommand::with_name("test") 179 | .about("controls testing features") 180 | .arg(Arg::with_name("debug") 181 | .short("d") 182 | .help("print debug information verbosely"))); 183 | 184 | // Parse the command line arguments 185 | let matches = app.get_matches(); 186 | 187 | let config = matches.value_of("config").unwrap_or("default.conf"); 188 | let input = matches.value_of("INPUT").unwrap(); 189 | 190 | // Handle subcommands 191 | match matches.subcommand() { 192 | ("clone", Some(sub_matches)) => { 193 | if matches.is_present("d") { 194 | // ... 195 | } 196 | }, 197 | ("push", Some(sub_matches)) => {}, 198 | ("commit", Some(sub_matches)) => {}, 199 | _ => {}, 200 | } 201 | } 202 | ``` 203 | 204 | **Alternatives**: [`docopt`] 205 | 206 |       207 | 208 | 209 | 210 | ### `encoding_rs = "0.6.11"`   [📖][d-encoding_rs] 211 | 212 | encoding_rs is a Gecko-oriented Free Software / Open Source 213 | implementation of the Encoding Standard in Rust. Gecko-oriented means 214 | that converting to and from UTF-16 is supported in addition to 215 | converting to and from UTF-8, that the performance and streamability 216 | goals are browser-oriented, and that FFI-friendliness is a goal. 217 | 218 | **Example**: [`examples/encoding_rs.rs`] 219 | 220 | ```rust 221 | extern crate encoding_rs; 222 | use encoding_rs::*; 223 | 224 | fn main() { 225 | let expected = "\u{30CF}\u{30ED}\u{30FC}\u{30FB}\u{30EF}\u{30FC}\u{30EB}\u{30C9}"; 226 | let encoded = b"\x83n\x83\x8D\x81[\x81E\x83\x8F\x81[\x83\x8B\x83h"; 227 | 228 | let (decoded, encoding_used, had_errors) = SHIFT_JIS.decode(encoded); 229 | 230 | assert_eq!(&decoded[..], expected); 231 | assert_eq!(encoding_used, SHIFT_JIS); 232 | assert!(!had_errors); 233 | 234 | println!("Decoded result: {}", decoded); 235 | } 236 | ``` 237 | 238 |       239 | 240 | 241 | 242 | ### `error-chain = "0.10.0"`   [📖][d-error-chain] 243 | 244 | Rust programs that handle errors consistently are reliable programs. 245 | Even after one understands [error handling] in Rust, it can be 246 | difficult to grasp and implement its best practices. `error-chain` 247 | helps you define your own error type that works with the `?` operator 248 | to make error handling in Rust simple and elegant. 249 | 250 | **Example**: [`examples/error-chain.rs`] 251 | 252 | ```rust,no_run,ignore 253 | // `error_chain!` can recurse deeply 254 | #![recursion_limit = "1024"] 255 | 256 | #[macro_use] 257 | extern crate error_chain; 258 | 259 | // We'll put our errors in an `errors` module, and other modules in 260 | // this crate will `use errors::*;` to get access to everything 261 | // `error_chain!` creates. 262 | mod errors { 263 | // Create the Error, ErrorKind, ResultExt, and Result types 264 | error_chain! { } 265 | } 266 | 267 | use errors::*; 268 | 269 | fn main() { 270 | if let Err(ref e) = run() { 271 | use ::std::io::Write; 272 | let stderr = &mut ::std::io::stderr(); 273 | let errmsg = "Error writing to stderr"; 274 | 275 | writeln!(stderr, "error: {}", e).expect(errmsg); 276 | 277 | for e in e.iter().skip(1) { 278 | writeln!(stderr, "caused by: {}", e).expect(errmsg); 279 | } 280 | 281 | // The backtrace is not always generated. Try to run this example 282 | // with `RUST_BACKTRACE=1`. 283 | if let Some(backtrace) = e.backtrace() { 284 | writeln!(stderr, "backtrace: {:?}", backtrace).expect(errmsg); 285 | } 286 | 287 | ::std::process::exit(1); 288 | } 289 | } 290 | 291 | // Most functions will return the `Result` type, imported from the 292 | // `errors` module. It is a typedef of the standard `Result` type 293 | // for which the error type is always our own `Error`. 294 | fn run() -> Result<()> { 295 | use std::fs::File; 296 | 297 | // Use chain_err to attach your own context to errors 298 | File::open("my secret file") 299 | .chain_err(|| "unable to open my secret file")?; 300 | 301 | // Use the `bail!` macro to return an error Result, ala `println!` 302 | bail!("giving up"); 303 | } 304 | ``` 305 | 306 | **Alternatives**: [`quick-error`] 307 | 308 |       309 | 310 | 311 | 312 | ### `flate2 = "0.2.19"`   [📖][d-flate2] 313 | 314 | Compression and decompression using the [DEFLATE] algorithm. 315 | 316 | **Example**: [`examples/flate2.rs`] 317 | 318 | ```rust,no_run 319 | extern crate flate2; 320 | extern crate tar; 321 | 322 | use flate2::read::GzDecoder; 323 | use std::env; 324 | use std::fs::File; 325 | use std::io::{self, BufReader}; 326 | use tar::Archive; 327 | 328 | fn run() -> Result<(), io::Error> { 329 | let mut args = env::args().skip(1); 330 | let tarball = args.next().expect("incorrect argument"); 331 | let outdir = args.next().expect("incorrect argument"); 332 | 333 | let archive = File::open(tarball)?; 334 | let archive = BufReader::new(archive); 335 | let archive = GzDecoder::new(archive)?; 336 | let mut archive = Archive::new(archive); 337 | 338 | archive.unpack(outdir)?; 339 | 340 | Ok(()) 341 | } 342 | 343 | fn main() { run().unwrap() } 344 | ``` 345 | 346 |       347 | 348 | 349 | ### `fnv = "1.0.5"`   [📖][d-fnv] 350 | 351 | The standard library's hash maps are notoriously slow for small keys (like 352 | integers). That's because they provide strong protection against a class of 353 | denial-of-service attacks called ["hash flooding"]. And that's a reasonable 354 | default. But when your `HashMap`s are a bottleneck consider reaching for this 355 | crate. It provides the Fowler-Noll-Vo hash function, and conveniences for 356 | creating FNV hash maps that are considerably faster than those in std. 357 | 358 | **Example**: [`examples/fnv.rs`] 359 | 360 | ```rust 361 | extern crate fnv; 362 | 363 | use fnv::FnvHashMap; 364 | 365 | fn main() { 366 | let mut map = FnvHashMap::default(); 367 | map.insert(1, "one"); 368 | map.insert(2, "two"); 369 | map.insert(3, "three"); 370 | 371 | for (number, word) in map.iter() { 372 | println!("Number {}: {}", number, word); 373 | } 374 | 375 | map.remove(&(2)); 376 | println!("The length of HashMap is {}.", map.len()); 377 | println!("The first element is {}.", map.get(&(1)).unwrap()); 378 | } 379 | ``` 380 | 381 |       382 | 383 | 384 | 385 | ### `itertools = "0.6.0"`   [📖][d-itertools] 386 | 387 | The Rust standard [`Iterator`] type provides a powerful abstraction for 388 | operating over sequences of values, and is used pervasively throughout 389 | Rust. There are though a number of common operations one might want to perform 390 | on sequences that are not provided by the standard library, and that's where 391 | itertools comes in. This crate has everything *including* the kitchen sink (in 392 | the form of the [`batching`] adaptor). Highlights include [`dedup`], [`group_by`], 393 | [`mend_slices`], [`merge`], [`sorted`], [`join`] and more. 394 | 395 | **Example**: [`examples/itertools.rs`] 396 | 397 | ```rust 398 | extern crate itertools; 399 | 400 | use itertools::{join, max, sorted}; 401 | 402 | fn main(){ 403 | let a = [3, 2, 5, 8, 7]; 404 | 405 | // Combine all iterator elements into one String, 406 | // seperated by *. 407 | println!("{:?}", join(&a, "*")); 408 | // Return the maximum value of the iterable. 409 | println!("{:?}", max(a.iter()).unwrap()); 410 | // Collect all the iterable's elements into a 411 | // sorted vector in ascending order. 412 | println!("{:?}", sorted(a.iter())); 413 | } 414 | ``` 415 | 416 |       417 | 418 | 419 | 420 | ### `lazy_static = "0.2.8"`   [📖][d-lazy_static] 421 | 422 | Rust has strict rules about accessing global state. In particular 423 | there is no ['life before main'] in Rust, so it's not possible to 424 | write a programmatic constructor for a global value that will be run 425 | at startup. Instead, Rust prefers lazy execution for global 426 | initialization, and the `lazy_static!` macro does just that. 427 | 428 | **Example**: [`examples/lazy_static.rs`] 429 | 430 | ```rust 431 | #[macro_use] 432 | extern crate lazy_static; 433 | 434 | use std::collections::HashMap; 435 | 436 | lazy_static! { 437 | static ref HASHMAP: HashMap = { 438 | let mut m = HashMap::new(); 439 | m.insert(0, "foo"); 440 | m.insert(1, "bar"); 441 | m.insert(2, "baz"); 442 | m 443 | }; 444 | static ref COUNT: usize = HASHMAP.len(); 445 | static ref NUMBER: u32 = times_two(21); 446 | } 447 | 448 | fn times_two(n: u32) -> u32 { n * 2 } 449 | 450 | fn main() { 451 | println!("The map has {} entries.", *COUNT); 452 | println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap()); 453 | println!("A expensive calculation on a static results in: {}.", *NUMBER); 454 | } 455 | ``` 456 | 457 |       458 | 459 | 460 | 461 | ### `libc = "0.2.25"`   [📖][d-libc] 462 | 463 | If you need to talk to foreign code, you need this crate. It exports C 464 | type and function definitions appropriate to each target platform Rust 465 | supports. It defines the standardized C features that are common 466 | across all platforms as well as non-standard features specific to the 467 | platform C libraries. For more platform-specific FFI definitions 468 | see [`nix`] and [`winapi`]. 469 | 470 | **Example**: [`examples/libc.rs`] 471 | 472 | ```rust 473 | extern crate libc; 474 | 475 | fn main() { 476 | unsafe { 477 | libc::exit(0); 478 | } 479 | } 480 | ``` 481 | 482 |       483 | 484 | 485 | 486 | ### `log = "0.3.8"`   [📖][d-log] 487 | 488 | The most common way to perform basic logging in Rust, with the 489 | [`error!`], [`warn!`], [`info!`], and [`debug!`] macros. It is often 490 | combined with the [`env_logger`] crate to get logging to the console, 491 | controlled by the [`RUST_LOG`] environment variable. This is the 492 | traditional logging crate used by `rustc`, and its functionality was 493 | once built in to the language. 494 | 495 | **Supplemental crates**: [`env_logger = "0.4.3"`] 496 | 497 | **Example**: [`examples/log.rs`] 498 | 499 | ```rust 500 | #[macro_use] 501 | extern crate log; 502 | extern crate env_logger; 503 | 504 | use log::LogLevel; 505 | 506 | fn main() { 507 | env_logger::init().unwrap(); 508 | 509 | debug!("this is a debug {}", "message"); 510 | error!("this is printed by default"); 511 | 512 | if log_enabled!(LogLevel::Info) { 513 | let x = 3 * 4; // expensive computation 514 | info!("the answer was: {}", x); 515 | } 516 | } 517 | ``` 518 | 519 | **Alternatives**: [`slog`], [`log4rs`] 520 | 521 |       522 | 523 | 524 | 525 | ### `memmap = "0.5.2"`   [📖][d-memmap] 526 | 527 | Cross-platform access to [memory-mapped I/O], a technique for sharing 528 | memory between processes, and for accessing the content of files as a 529 | simple array of bytes. It is implemented by binding the [`mmap`] 530 | syscall on Unix, and the [`CreateFileMapping`] / [`MapViewOfFile`] 531 | functions on Windows. This is a low-level feature used to build other 532 | abstractions. Note that it's not generally possible to create safe 533 | abstractions for memory mapping, since memory mapping entails shared 534 | access to resources outside of Rust's control. As such, the APIs 535 | in this crate are unsafe. 536 | 537 | **Example**: [`examples/memmap.rs`] 538 | 539 | [`examples/memmap.rs`]: examples/memmap.rs 540 | 541 | ```rust,no_run 542 | extern crate memmap; 543 | 544 | use memmap::{Mmap, Protection}; 545 | use std::env; 546 | use std::io; 547 | use std::str; 548 | 549 | fn run() -> Result<(), io::Error> { 550 | let mut args = env::args().skip(1); 551 | let input = args.next().expect("incorrect argument"); 552 | 553 | let map = Mmap::open_path(input, Protection::Read)?; 554 | unsafe { 555 | let all_bytes = map.as_slice(); 556 | if let Ok(file_str) = str::from_utf8(all_bytes) { 557 | println!("{}", file_str); 558 | } else { 559 | println!("not utf8"); 560 | } 561 | } 562 | Ok(()) 563 | } 564 | 565 | fn main() { run().unwrap() } 566 | ``` 567 | 568 |       569 | 570 | 571 | 572 | ### `ndarray = "0.9.1"`   [📖][d-ndarray] 573 | 574 | The ndarray crate provides an N-dimensional container for general 575 | elements and for numerics. The multidimensional array, otherwise known 576 | as a "matrix", is a core data structure for numerical applications, 577 | and Rust does not have one in the language or standard library. 578 | 579 | **Example**: [`examples/ndarray.rs`] 580 | 581 | ```rust 582 | #[macro_use(s)] 583 | extern crate ndarray; 584 | 585 | use ndarray::{Array3, arr3}; 586 | 587 | fn main() { 588 | // Create a three-dimensional f64 array, initialized with zeros 589 | let mut temperature = Array3::::zeros((3, 4, 5)); 590 | 591 | // Increase the temperature in this location, notice the 592 | // double-brackets indexing `temperature` 593 | temperature[[2, 2, 2]] += 0.5; 594 | 595 | // Create a 3-dimensional matrix, 596 | // 2 submatrices of 2 rows with 3 elements per row, means a shape 597 | // of `[2, 2, 3]`. 598 | let a = arr3(&[[[ 1, 2, 3], // -- 2 rows \_ 599 | [ 4, 5, 6]], // -- / 600 | [[ 7, 8, 9], // \_ 2 submatrices 601 | [10, 11, 12]]]); // / 602 | // 3 columns ..../.../.../ 603 | 604 | // This is a 2 x 2 x 3 array 605 | assert_eq!(a.shape(), &[2, 2, 3]); 606 | 607 | // Let’s create a slice of `a` with 608 | // 609 | // - Both of the submatrices of the greatest dimension: `..` 610 | // - Only the first row in each submatrix: `0..1` 611 | // - Every element in each row: `..` 612 | let b = a.slice(s![.., 0..1, ..]); 613 | 614 | // This is the result of the above slice into `a` 615 | let c = arr3(&[[[ 1, 2, 3]], 616 | [[ 7, 8, 9]]]); 617 | assert_eq!(b, c); 618 | assert_eq!(b.shape(), &[2, 1, 3]); 619 | } 620 | ``` 621 | 622 |       623 | 624 | 625 | 626 | ### `num = "0.1.40"`   [📖][d-num] 627 | 628 | Big integers, rational numbers, complex numbers, and numeric 629 | traits. This crate has a long history, beginning life in the standard 630 | library, being moved into the rust-lang organization, and finally 631 | being adopted by community maintainers. It remains a common way to 632 | access the kinds of features it provides. 633 | 634 | **Example**: [`examples/num.rs`] 635 | 636 | ```rust 637 | extern crate num; 638 | 639 | use num::FromPrimitive; 640 | use num::bigint::BigInt; 641 | use num::rational::{Ratio, BigRational}; 642 | 643 | fn approx_sqrt(number: u64, iterations: usize) -> BigRational { 644 | let start: Ratio 645 | = Ratio::from_integer(FromPrimitive::from_u64(number).unwrap()); 646 | 647 | let mut approx = start.clone(); 648 | 649 | for _ in 0..iterations { 650 | approx = (&approx + (&start / &approx)) / 651 | Ratio::from_integer(FromPrimitive::from_u64(2).unwrap()); 652 | } 653 | 654 | approx 655 | } 656 | 657 | fn main() { 658 | println!("{}", approx_sqrt(10, 4)); // prints 4057691201/1283082416 659 | } 660 | ``` 661 | 662 |       663 | 664 | 665 | ### `num_cpus = "1.6.2"`   [📖][d-num_cpus] 666 | 667 | When you need to make things parallel, you need to know how many CPUs 668 | to use! This is the simple way to get that information. 669 | 670 | **Example**: [`examples/num_cpus.rs`] 671 | 672 | ```rust 673 | extern crate threadpool; 674 | extern crate num_cpus; 675 | 676 | use threadpool::ThreadPool; 677 | use std::sync::mpsc::channel; 678 | 679 | fn main() { 680 | // Get the number of cpus on current machine 681 | let n_workers = num_cpus::get(); 682 | let n_jobs = 8; 683 | 684 | // Create the thread pool with amount of workers equal to cores 685 | let pool = ThreadPool::new(n_workers); 686 | 687 | // Create transmitter and receiver channel 688 | let (tx, rx) = channel(); 689 | 690 | // For each job grab a free worker from the pool and execute 691 | for _ in 0..n_jobs { 692 | let tx = tx.clone(); 693 | pool.execute(move || { 694 | tx.send(1).unwrap(); 695 | }); 696 | } 697 | 698 | assert_eq!(rx.iter().take(n_jobs).fold(0, |a, b| a + b), 8); 699 | } 700 | ``` 701 | 702 |       703 | 704 | 705 | 706 | ### `rand = "0.3.15"`   [📖][d-rand] 707 | 708 | Random number generators. The defaults are cryptographically 709 | strong. This is another crate with a long history, beginning life in 710 | the standard library. 711 | 712 | **Example**: [`examples/rand.rs`] 713 | 714 | ```rust 715 | extern crate rand; 716 | 717 | use rand::Rng; 718 | 719 | fn main() { 720 | let mut rng = rand::thread_rng(); 721 | if rng.gen() { // random bool 722 | println!("i32: {}, u32: {}", rng.gen::(), rng.gen::()) 723 | } 724 | 725 | let tuple = rand::random::<(f64, char)>(); 726 | println!("{:?}", tuple) 727 | } 728 | ``` 729 | 730 |       731 | 732 | 733 | 734 | ### `rayon = "0.8.2"`   [📖][d-rayon] 735 | 736 | When people say that Rust makes parallelism easy, this is why. Rayon 737 | provides parallel iterators that make expressing efficient parallel 738 | operations simple and foolproof. 739 | 740 | **Example**: [`examples/rayon.rs`] 741 | 742 | ```rust 743 | extern crate rayon; 744 | 745 | use rayon::prelude::*; 746 | 747 | fn main() { 748 | let mut input = (0..1000).collect::>(); 749 | 750 | // Calculate the sum of squares 751 | let sq_sum: i32 = input.par_iter() 752 | .map(|&i| i * i) 753 | .sum(); 754 | 755 | // Increment each element in parallel 756 | input.par_iter_mut() 757 | .for_each(|p| *p += 1); 758 | 759 | // Parallel quicksort 760 | let mut input = (0..1000).rev().collect::>(); 761 | quick_sort(&mut input); 762 | } 763 | 764 | fn quick_sort(v: &mut [T]) { 765 | if v.len() <= 1 { 766 | return; 767 | } 768 | 769 | let mid = partition(v); 770 | let (lo, hi) = v.split_at_mut(mid); 771 | rayon::join(|| quick_sort(lo), || quick_sort(hi)); 772 | } 773 | 774 | fn partition(v: &mut [T]) -> usize { 775 | let pivot = v.len() - 1; 776 | let mut i = 0; 777 | for j in 0..pivot { 778 | if v[j] <= v[pivot] { 779 | v.swap(i, j); 780 | i += 1; 781 | } 782 | } 783 | v.swap(i, pivot); 784 | i 785 | } 786 | ``` 787 | 788 |       789 | 790 | 791 | 792 | ### `regex = "0.2.2"`   [📖][d-regex] 793 | 794 | Rust's regular expressions are [fast], like Rust is fast. Part of 795 | their power comes from a careful design that disallows back-references 796 | and arbitrary lookahead, creating predictable worst-case performance. 797 | 798 | **Example**: [`examples/regex.rs`] 799 | 800 | ```rust 801 | extern crate regex; 802 | 803 | use regex::Regex; 804 | 805 | fn main() { 806 | // Find a date 807 | let re = Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap(); 808 | assert!(re.is_match("2014-01-01")); 809 | 810 | // Iterating over capture groups 811 | let re = Regex::new(r"(\d{4})-(\d{2})-(\d{2})").unwrap(); 812 | let text = "2012-03-14, 2013-01-01 and 2014-07-05"; 813 | for cap in re.captures_iter(text) { 814 | println!("Month: {} Day: {} Year: {}", &cap[2], &cap[3], &cap[1]); 815 | } 816 | } 817 | ``` 818 | 819 |       820 | 821 | 822 | 823 | ### `reqwest = "0.7.1"`   [📖][d-reqwest] 824 | 825 | A simple HTTP and HTTPS client. It is built on the popular Rust HTTP 826 | implementation, [hyper], which is the HTTP stack developed for 827 | [Servo]. 828 | 829 | **Example**: [`examples/reqwest.rs`] 830 | 831 | ```rust,no_run 832 | extern crate reqwest; 833 | 834 | use std::collections::HashMap; 835 | use std::io::{BufRead, BufReader}; 836 | 837 | fn main() { 838 | // Make a GET request 839 | let resp = reqwest::get("https://www.rust-lang.org").unwrap(); 840 | assert!(resp.status().is_success()); 841 | 842 | let lines = BufReader::new(resp) 843 | .lines() 844 | .filter_map(|l| l.ok()) 845 | .take(10); 846 | for line in lines { 847 | println!("{}", line); 848 | } 849 | 850 | // Make a POST request 851 | let client = reqwest::Client::new().unwrap(); 852 | let res = client.post("http://httpbin.org/post").unwrap() 853 | .body("the exact body that is sent") 854 | .send(); 855 | 856 | // Convert to/from JSON automatically 857 | let mut map = HashMap::new(); 858 | map.insert("lang", "rust"); 859 | map.insert("body", "json"); 860 | 861 | // This will POST a body of `{"lang":"rust","body":"json"}` 862 | let client = reqwest::Client::new().unwrap(); 863 | let res = client.post("http://httpbin.org/post").unwrap() 864 | .json(&map).unwrap() 865 | .send(); 866 | } 867 | ``` 868 | 869 |       870 | 871 | 872 | 873 | ### `semver = "0.7.0"`   [📖][d-semver] 874 | 875 | Rust uses [semantic versioning][semver] (also known as "semver") for 876 | crate versioning. This crate provides the canonical semver 877 | representation for Rust. 878 | 879 | **Example**: [`examples/semver.rs`] 880 | 881 | ```rust 882 | extern crate semver; 883 | 884 | use semver::Version; 885 | 886 | fn main() { 887 | // Construct Version objects 888 | assert!(Version::parse("1.2.3") == Ok(Version { 889 | major: 1, 890 | minor: 2, 891 | patch: 3, 892 | pre: vec!(), 893 | build: vec!(), 894 | })); 895 | 896 | // Compare Versions 897 | assert!(Version::parse("1.2.3-alpha") != Version::parse("1.2.3-beta")); 898 | assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.0")); 899 | 900 | // Increment patch number of mutable Version 901 | let mut bugfix_release = Version::parse("1.0.0").unwrap(); 902 | bugfix_release.increment_patch(); 903 | 904 | assert_eq!(Ok(bugfix_release), Version::parse("1.0.1")); 905 | } 906 | ``` 907 | 908 |       909 | 910 | 911 | 912 | ### `serde = "1.0.10"`   [📖][d-serde] 913 | 914 | Serialization and deserialization of Rust datastructures is fast 915 | and easy using the `serde` serialization framework. Simply 916 | tag your data structures with `#[derive(Serialize, Deserialize)]` 917 | and serde will automatically convert them between formats like 918 | JSON, TOML, YAML, and more. To best understand serde, read 919 | its documentation at [serde.rs]. 920 | 921 | **Supplemental crates**: [`serde_derive = "1.0.10"`], 922 | [`serde_json = "1.0.2"`], 923 | [`toml = "0.4.2"`] 924 | 925 | **Example**: [`examples/serde.rs`] 926 | 927 | ```rust 928 | #[macro_use] 929 | extern crate serde_derive; 930 | extern crate serde_json; 931 | 932 | use serde_json::Value; 933 | 934 | #[derive(Serialize, Deserialize, Debug)] 935 | struct Contact { 936 | name: String, 937 | age: u32, 938 | } 939 | 940 | fn main() { 941 | let contact = Contact { 942 | name: "Brian".to_string(), 943 | age: 21, 944 | }; 945 | 946 | // Serialize data structures to strings in JSON format 947 | let contact: String = serde_json::to_string(&contact).unwrap(); 948 | println!("{}", contact); 949 | 950 | // Deserialize data structures from JSON strings 951 | let contact: Contact = serde_json::from_str(&contact).unwrap(); 952 | println!("{:?}", contact); 953 | 954 | // Convert to arbitrary JSON `Value` type 955 | let contact: Value = serde_json::to_value(&contact).unwrap(); 956 | println!("{:?}", contact); 957 | } 958 | ``` 959 | 960 | **Alternatives**: [`rustc-serialize`] 961 | 962 |       963 | 964 | 965 | 966 | ### `serde_json = "1.0.2"`   [📖][d-serde_json] 967 | 968 | Access to [JSON], the "JavaScript Object Notation" format, 969 | widely used for transmission and storage of data on the Internet. 970 | This crate can be used for reading, writing, and manipulation 971 | of arbitrary JSON in addition to its use for automatic serialization 972 | with [serde](#serde). 973 | 974 | **Example**: [`examples/json.rs`] 975 | 976 | ```rust 977 | extern crate serde_json; 978 | 979 | use serde_json::Value; 980 | 981 | fn main() { 982 | // Some JSON input data as a &str. Maybe this comes from the user. 983 | let data = r#"{ 984 | "name": "John Doe", 985 | "age": 43, 986 | "phones": [ 987 | "+44 1234567", 988 | "+44 2345678" 989 | ] 990 | }"#; 991 | 992 | // Parse the string of data into serde_json::Value. 993 | let v: Value = serde_json::from_str(data).unwrap(); 994 | 995 | // Access parts of the data by indexing with square brackets. 996 | println!("Please call {} at the number {}", v["name"], v["phones"][0]); 997 | } 998 | ``` 999 | 1000 | **Alternatives**: [`json`] 1001 | 1002 |       1003 | 1004 | 1005 | 1006 | ### `tar = "0.4.23"`   [📖][d-tar] 1007 | 1008 | The "tar" archive format is in common use on the web. It is most often 1009 | found in the form of `.tar.gz` files (called "tarballs") that have 1010 | been compressed with the [DEFLATE] algorithm, which the `tar` crate 1011 | can decompress when paired with the [`flate2`][flate2] crate. 1012 | 1013 | **Example**: [`examples/tar.rs`] 1014 | 1015 | ```rust,no_run 1016 | extern crate flate2; 1017 | extern crate tar; 1018 | 1019 | use flate2::read::GzDecoder; 1020 | use std::env; 1021 | use std::fs::File; 1022 | use std::io::{self, BufReader}; 1023 | use tar::Archive; 1024 | 1025 | fn run() -> Result<(), io::Error> { 1026 | let mut args = env::args().skip(1); 1027 | let tarball = args.next().expect("incorrect argument"); 1028 | let outdir = args.next().expect("incorrect argument"); 1029 | 1030 | let archive = File::open(tarball)?; 1031 | let archive = BufReader::new(archive); 1032 | let archive = GzDecoder::new(archive)?; 1033 | let mut archive = Archive::new(archive); 1034 | 1035 | archive.unpack(outdir)?; 1036 | 1037 | Ok(()) 1038 | } 1039 | 1040 | fn main() { run().unwrap() } 1041 | ``` 1042 | 1043 |       1044 | 1045 | 1046 | 1047 | ### `tempdir = "0.3.5"`   [📖][d-tempdir] 1048 | 1049 | The most common way to create temporary directories in Rust, 1050 | this crate was once part of the standard library. 1051 | 1052 | **Example**: [`examples/tempdir.rs`] 1053 | 1054 | ```rust 1055 | extern crate tempdir; 1056 | 1057 | use std::fs::File; 1058 | use std::io::Write; 1059 | use tempdir::TempDir; 1060 | 1061 | fn main() { 1062 | // Create a directory inside of `std::env::temp_dir()`, named with 1063 | // the prefix "example". 1064 | let tmp_dir = TempDir::new("example").expect("create temp dir"); 1065 | let file_path = tmp_dir.path().join("my-temporary-note.txt"); 1066 | let mut tmp_file = File::create(file_path).expect("create temp file"); 1067 | writeln!(tmp_file, "Brian was here. Briefly.").expect("write temp file"); 1068 | 1069 | // By closing the `TempDir` explicitly, we can check that it has 1070 | // been deleted successfully. If we don't close it explicitly, 1071 | // the directory will still be deleted when `tmp_dir` goes out 1072 | // of scope, but we won't know whether deleting the directory 1073 | // succeeded. 1074 | drop(tmp_file); 1075 | tmp_dir.close().expect("delete temp dir"); 1076 | } 1077 | ``` 1078 | 1079 |       1080 | 1081 | 1082 | 1083 | ### `threadpool = "1.4.0"`   [📖][d-threadpool] 1084 | 1085 | A thread pool for running a number of jobs on a fixed set of worker threads. 1086 | 1087 | **Example**: [`examples/threadpool.rs`] 1088 | 1089 | ```rust 1090 | extern crate threadpool; 1091 | extern crate num_cpus; 1092 | 1093 | use threadpool::ThreadPool; 1094 | use std::sync::mpsc::channel; 1095 | 1096 | fn main() { 1097 | // Get the number of cpus on current machine 1098 | let n_workers = num_cpus::get(); 1099 | let n_jobs = 8; 1100 | 1101 | // Create the thread pool with amount of workers equal to cores 1102 | let pool = ThreadPool::new(n_workers); 1103 | 1104 | // Create transmitter and receiver channel 1105 | let (tx, rx) = channel(); 1106 | 1107 | // For each job grab a free worker from the pool and execute 1108 | for _ in 0..n_jobs { 1109 | let tx = tx.clone(); 1110 | pool.execute(move || { 1111 | tx.send(1).unwrap(); 1112 | }); 1113 | } 1114 | 1115 | assert_eq!(rx.iter().take(n_jobs).fold(0, |a, b| a + b), 8); 1116 | } 1117 | ``` 1118 | 1119 | **Alternatives**: [`scoped_threadpool`] 1120 | 1121 |       1122 | 1123 | 1124 | ### `toml = "0.4.2"`   [📖][d-toml] 1125 | 1126 | [TOML](https://github.com/toml-lang/toml) is a common format for 1127 | configuration files, like [Cargo.toml]. It's easy on the eyes, simple 1128 | to parse, and serializes from Rust types with [`serde`](#serde). 1129 | 1130 | **Example**: [`examples/toml.rs`] 1131 | 1132 | ```rust 1133 | extern crate toml; 1134 | 1135 | use toml::Value; 1136 | 1137 | fn main() { 1138 | let toml = r#" 1139 | [test] 1140 | foo = "bar" 1141 | "#; 1142 | 1143 | let value = toml.parse::().unwrap(); 1144 | println!("{:?}", value); 1145 | } 1146 | ``` 1147 | 1148 |       1149 | 1150 | 1151 | 1152 | ### `url = "1.5.1"`   [📖][d-url] 1153 | 1154 | The URL parser and type, originally created for [Servo]. 1155 | 1156 | **Example**: [`examples/url.rs`] 1157 | 1158 | ```rust 1159 | extern crate url; 1160 | 1161 | use url::{Url, Host}; 1162 | 1163 | fn main() { 1164 | let issue_list_url = Url::parse( 1165 | "https://github.com/rust-lang/rust/issues?labels=E-easy&state=open" 1166 | ).unwrap(); 1167 | 1168 | assert!(issue_list_url.scheme() == "https"); 1169 | assert!(issue_list_url.username() == ""); 1170 | assert!(issue_list_url.password() == None); 1171 | assert!(issue_list_url.host_str() == Some("github.com")); 1172 | assert!(issue_list_url.host() == Some(Host::Domain("github.com"))); 1173 | assert!(issue_list_url.port() == None); 1174 | assert!(issue_list_url.path() == "/rust-lang/rust/issues"); 1175 | assert!(issue_list_url.path_segments().map(|c| c.collect::>()) == 1176 | Some(vec!["rust-lang", "rust", "issues"])); 1177 | assert!(issue_list_url.query() == Some("labels=E-easy&state=open")); 1178 | assert!(issue_list_url.fragment() == None); 1179 | assert!(!issue_list_url.cannot_be_a_base()); 1180 | } 1181 | ``` 1182 | 1183 |       1184 | 1185 | 1186 | 1187 | ### `walkdir = "1.0.7"`   [📖][d-walkdir] 1188 | 1189 | A cross platform Rust library for efficiently walking a directory 1190 | recursively. Note the [`filter_entry`] method on the directory 1191 | iterator that short-circuits decent into subdirectories. 1192 | 1193 | **Example**: [`examples/walkdir.rs`] 1194 | 1195 | ```rust 1196 | extern crate walkdir; 1197 | 1198 | use walkdir::{WalkDir, Error}; 1199 | 1200 | fn run() -> Result<(), Error> { 1201 | let wd = WalkDir::new("."); 1202 | 1203 | for entry in wd { 1204 | let entry = entry?; 1205 | println!("{}", entry.path().display()); 1206 | } 1207 | 1208 | Ok(()) 1209 | } 1210 | 1211 | fn main() { run().unwrap(); } 1212 | ``` 1213 | 1214 |       1215 | 1216 | 1217 | ## About `stdx` 1218 | 1219 | Rust has a lovely and portable standard library, but it is not 1220 | featureful enough to write software of any great 1221 | sophistication. Compared to common platforms including Java, Python, 1222 | and Go, Rust's standard library is small. 1223 | 1224 | In Rust, the libraries we use for even simple tasks live and evolve on 1225 | [crates.io]. This affords the Rust community freedom to experiment - 1226 | discovering the Rustiest solutions to even common problems can take 1227 | quite some iteration - but it also means that we're in for a slow 1228 | evolutionary process to converge around the best of those solutions. In 1229 | the meantime, you just have to know which crates to use for what. 1230 | 1231 | `stdx` contains some of the most important crates in Rust. I mean 1232 | it. If Rust had a more expansive standard library, many of the `stdx` 1233 | crates would be in it, or at least the features they provide. Many of 1234 | the crates of `stdx` are maintained by the same authors as the Rust 1235 | standard library, and they are designed to be idiomatic and 1236 | interoperable. These are core elements of the crate ecosystem that 1237 | all Rusticians should be aware of. 1238 | 1239 | [crates.io]: https://www.crates.io 1240 | 1241 | ## How to use `stdx` 1242 | 1243 | `stdx` is primarily a teaching tool. New and old Rust programmers 1244 | alike will get the most from it by digesting [the list](#list) of 1245 | `stdx` crates, each entry of which links to a description of the crate 1246 | along with _an example of its basic use_. 1247 | 1248 | These examples are full working source and are intended to get you 1249 | up and running with any of the `stdx` crates _immediately_. Just 1250 | copy the crate name and version exactly as written into the `dependencies` 1251 | section of your `Cargo.toml` like so: 1252 | 1253 | ```toml 1254 | [dependencies] 1255 | bitflags = "0.9.1" 1256 | ``` 1257 | 1258 | Then copy the full example into your `examples` directory, like 1259 | so: 1260 | 1261 | **Example**: [`examples/bitflags.rs`] 1262 | 1263 | ```rust 1264 | #[macro_use] 1265 | extern crate bitflags; 1266 | 1267 | bitflags! { 1268 | struct Flags: u32 { 1269 | const FLAG_A = 0b00000001; 1270 | const FLAG_B = 0b00000010; 1271 | const FLAG_C = 0b00000100; 1272 | const FLAG_ABC = FLAG_A.bits 1273 | | FLAG_B.bits 1274 | | FLAG_C.bits; 1275 | } 1276 | } 1277 | 1278 | fn main() { 1279 | let e1 = FLAG_A | FLAG_C; 1280 | let e2 = FLAG_B | FLAG_C; 1281 | assert_eq!((e1 | e2), FLAG_ABC); // union 1282 | assert_eq!((e1 & e2), FLAG_C); // intersection 1283 | assert_eq!((e1 - e2), FLAG_A); // set difference 1284 | assert_eq!(!e2, FLAG_A); // set complement 1285 | } 1286 | ``` 1287 | 1288 | Then execute the following: 1289 | 1290 | ```sh 1291 | cargo run --example bitflags 1292 | ``` 1293 | 1294 | And suddenly you are a slightly-experienced user of that crate. 1295 | Now click on the [📖][d-bitflags] icon to get the rest of the story. 1296 | 1297 | Convinced? [Go check out that list](#list). 1298 | 1299 | 1300 | ## Why use `stdx`? 1301 | 1302 | As a learning tool, I hope the benefit will be evident from a straight 1303 | read-through. But `stdx`, and tools like it, may provide important 1304 | benefits to users in the future. 1305 | 1306 | To be clear, `stdx` is experimental. A lot of the below is 1307 | speculative. 1308 | 1309 | `stdx` provides assurances that the versions of crates it specifes 1310 | work together correctly in a wide variety of configurations. Today 1311 | those assurances are few, but they will grow. And these types of 1312 | assurances will become increasingly valuable to Rust. 1313 | 1314 | As of now, the only validation `stdx` provides is that the exact 1315 | versions of the `stdx` crates resolve correctly by Cargo, and that 1316 | they build on Linux and Windows. That is already beneficial by 1317 | uncovering problematic combinations and incorrect semver 1318 | specifications. Here are some other assurances that `stdx` will 1319 | enable: 1320 | 1321 | * Additional integration test cases between the `stdx` crates 1322 | * Testing of all `stdx` crates' own test suites using the `stdx` version lock 1323 | * Testing on all tier 1 platforms 1324 | * Testing on tier 2 platforms 1325 | * Enforcement and coverage of `serde` features and interop 1326 | * Enforcement of other compile-time feature standards 1327 | * `stdx` as version lock - you don't even have to call into it. Just 1328 | link to it and it locks down a chunk of your crate graph to 1329 | known-good combinaitons. 1330 | * Ecosystem wide testing using `stdx` version lock - eventually we 1331 | will be able to say which crates are known to work correctly 1332 | with `stdx`. 1333 | * The more people use the `stdx` version lock the more assurance they 1334 | get. This plays into future Rust's LTS directions. 1335 | 1336 | By applying high quality standards to a small selection of critical 1337 | crates we can create a high degree of confidence in a larger core of 1338 | the Rust ecosystem. 1339 | 1340 | 1341 | ## Selection criteria 1342 | 1343 | The criteria for inclusion in `stdx` is conservative, and fuzzy. It's 1344 | mostly crates that are pretty super important, considering criteria 1345 | like 1346 | 1347 | - portability 1348 | - quality 1349 | - conformance to conventions 1350 | - documentation 1351 | - interoperability with other crates 1352 | - reliability of maintainers 1353 | - de-facto adoption 1354 | - historical context and precedent 1355 | 1356 | `stdx` is focused on core features, crates that are quintessentially 1357 | Rust and relied on by many Rust programs. It is intentionally 1358 | limited for the sake of simplicity and ease of comprehension. 1359 | 1360 | All crates must work on Rust's tier-1 platforms, currently x86 Linux, 1361 | OS X, and Windows. 1362 | 1363 | 1364 | ## Contributing 1365 | 1366 | See [CONTRIBUTING.md](CONTRIBUTING.md). 1367 | 1368 | 1369 | ## License 1370 | 1371 | `stdx` and the crates it links to are licensed under various 1372 | [permissive, BSD-like][perm] licenses. In lay-terms these licenses 1373 | allow their code to be used and distributed freely, and are compatible 1374 | with [Rust's own license (MIT/Apache 2)][rustlice]. 1375 | 1376 | `stdx` itself is dual MIT/Apache 2 licensed, like Rust, and the 1377 | copyright is owned by its contributors. 1378 | 1379 | [perm]: https://en.wikipedia.org/wiki/Permissive_free_software_licence 1380 | [rustlice]: https://github.com/rust-lang/rust/blob/master/COPYRIGHT 1381 | 1382 | 1383 | 1384 | 1385 | 1386 | 1387 | [`bitflags = "0.9.1"`]: #bitflags 1388 | [`byteorder = "1.1.0"`]: #byteorder 1389 | [`chrono = "0.4.0"`]: #chrono 1390 | [`clap = "2.25.0"`]: #clap 1391 | [`encoding_rs = "0.6.11"`]: #encoding_rs 1392 | [`error-chain = "0.10.0"`]: #error-chain 1393 | [`flate2 = "0.2.19"`]: #flate2 1394 | [`fnv = "1.0.5"`]: #fnv 1395 | [`itertools = "0.6.0"`]: #itertools 1396 | [`serde_json = "1.0.2"`]: #serde_json 1397 | [`lazy_static = "0.2.8"`]: #lazy_static 1398 | [`libc = "0.2.25"`]: #libc 1399 | [`log = "0.3.8"`]: #log 1400 | [`memmap = "0.5.2"`]: #memmap 1401 | [`ndarray = "0.9.1"`]: #ndarray 1402 | [`num = "0.1.40"`]: #num 1403 | [`num_cpus = "1.6.2"`]: #num_cpus 1404 | [`rand = "0.3.15"`]: #rand 1405 | [`rayon = "0.8.2"`]: #rayon 1406 | [`regex = "0.2.2"`]: #regex 1407 | [`reqwest = "0.7.1"`]: #reqwest 1408 | [`semver = "0.7.0"`]: #semver 1409 | [`serde = "1.0.10"`]: #serde 1410 | [`tar = "0.4.23"`]: #tar 1411 | [`tempdir = "0.3.5"`]: #tempdir 1412 | [`threadpool = "1.4.0"`]: #threadpool 1413 | [`toml = "0.4.2"`]: #toml 1414 | [`url = "1.5.1"`]: #url 1415 | [`walkdir = "1.0.7"`]: #walkdir 1416 | 1417 | 1418 | 1419 | [d-bitflags]: https://docs.rs/bitflags/0.9.1/bitflags/ 1420 | [d-byteorder]: https://docs.rs/byteorder/1.1.0/byteorder/ 1421 | [d-chrono]: https://docs.rs/chrono/0.4.0/chrono/ 1422 | [d-clap]: https://docs.rs/clap/2.25.0/clap/ 1423 | [d-encoding_rs]: https://docs.rs/encoding_rs/0.6.11/encoding_rs/ 1424 | [d-error-chain]: https://docs.rs/error-chain/0.8.1/error_chain/ 1425 | [d-flate2]: https://docs.rs/flate2/0.2.19/flate2/ 1426 | [d-fnv]: https://docs.rs/fnv/1.0.5/fnv/ 1427 | [d-itertools]: https://docs.rs/itertools/0.6.0/itertools/ 1428 | [d-lazy_static]: https://docs.rs/lazy_static/0.2.8/lazy_static 1429 | [d-libc]: https://docs.rs/libc/0.2.25/libc/ 1430 | [d-log]: https://docs.rs/log/0.3.8/log/ 1431 | [d-memmap]: https://docs.rs/memmap/0.5.2/memmap/ 1432 | [d-ndarray]: https://docs.rs/ndarray/0.9.1/ndarray/ 1433 | [d-num]: https://docs.rs/num/0.1.40/num/ 1434 | [d-num_cpus]: https://docs.rs/num_cpus/1.6.2/num_cpus/ 1435 | [d-rand]: https://docs.rs/rand/0.3.15/rand/ 1436 | [d-rayon]: https://docs.rs/rayon/0.8.2/rayon/ 1437 | [d-regex]: https://docs.rs/regex/0.2.2/regex/ 1438 | [d-reqwest]: https://docs.rs/reqwest/0.7.1/reqwest/ 1439 | [d-serde]: https://docs.rs/serde/1.0.10/serde/ 1440 | [d-serde_json]: https://docs.rs/serde_json/1.0.2/serde_json/ 1441 | [d-tar]: https://docs.rs/tar/0.4.23/tar/ 1442 | [d-tempdir]: https://docs.rs/tempdir/0.3.5/tempdir/ 1443 | [d-threadpool]: https://docs.rs/threadpool/1.4.0/threadpool/ 1444 | [d-toml]: https://docs.rs/toml/0.4.2/toml/ 1445 | [d-url]: https://docs.rs/url/1.5.1/url/ 1446 | [d-walkdir]: https://docs.rs/walkdir/1/walkdir/ 1447 | [d-semver]: https://docs.rs/semver/0.7.0/semver/ 1448 | 1449 | 1450 | 1451 | [`examples/bitflags.rs`]: examples/bitflags.rs 1452 | [`examples/byteorder.rs`]: examples/byteorder.rs 1453 | [`examples/chrono.rs`]: examples/chrono.rs 1454 | [`examples/clap.rs`]: examples/clap.rs 1455 | [`examples/encoding_rs.rs`]: examples/encoding_rs.rs 1456 | [`examples/error-chain.rs`]: examples/error-chain.rs 1457 | [`examples/flate2.rs`]: examples/flate2.rs 1458 | [`examples/fnv.rs`]: examples/fnv.rs 1459 | [`examples/itertools.rs`]: examples/itertools.rs 1460 | [`examples/lazy_static.rs`]: examples/lazy_static.rs 1461 | [`examples/libc.rs`]: examples/libc.rs 1462 | [`examples/log.rs`]: examples/log.rs 1463 | [`examples/ndarray.rs`]: examples/ndarray.rs 1464 | [`examples/num.rs`]: examples/num.rs 1465 | [`examples/num_cpus.rs`]: examples/num_cpus.rs 1466 | [`examples/rand.rs`]: examples/rand.rs 1467 | [`examples/rayon.rs`]: examples/rayon.rs 1468 | [`examples/regex.rs`]: examples/regex.rs 1469 | [`examples/reqwest.rs`]: examples/reqwest.rs 1470 | [`examples/serde.rs`]: examples/serde.rs 1471 | [`examples/semver.rs`]: examples/semver.rs 1472 | [`examples/json.rs`]: examples/json.rs 1473 | [`examples/tar.rs`]: examples/tar.rs 1474 | [`examples/tempdir.rs`]: examples/tempdir.rs 1475 | [`examples/threadpool.rs`]: examples/threadpool.rs 1476 | [`examples/toml.rs`]: examples/toml.rs 1477 | [`examples/url.rs`]: examples/url.rs 1478 | [`examples/walkdir.rs`]: examples/walkdir.rs 1479 | 1480 | 1481 | 1482 | [`env_logger = "0.4.3"`]: https://docs.rs/env_logger/0.4.3/env_logger/ 1483 | [`serde_derive = "1.0.10"`]: https://docs.rs/serde_derive/1.0.10/serde_derive 1484 | 1485 | 1486 | 1487 | [`json`]: https://docs.rs/json 1488 | [`log4rs`]: https://docs.rs/log4rs 1489 | [`rustc-serialize`]: https://docs.rs/rustc-serialize 1490 | [`slog`]: https://docs.rs/slog 1491 | [`quick-error`]: https://docs.rs/quick-error 1492 | [`docopt`]: https://docs.rs/docopt 1493 | [`scoped_threadpool`]: https://docs.rs/scoped_threadpool 1494 | 1495 | 1496 | 1497 | [DEFLATE]: https://en.wikipedia.org/wiki/DEFLATE 1498 | [error handling]: https://rust-lang.github.io/book/second-edition/ch09-00-error-handling.html 1499 | ['life before main']: https://isocpp.org/wiki/faq/ctors#static-init-order 1500 | [fast]: http://blog.burntsushi.net/ripgrep/ 1501 | [flate2]: #flate2 1502 | [JSON]: http://json.org/ 1503 | [Cargo.toml]: http://doc.crates.io/manifest.html 1504 | [Servo]: https://servo.org 1505 | [`filter_entry`]: https://docs.rs/walkdir/1.0/walkdir/trait.WalkDirIterator.html#method.filter_entry 1506 | ["hash flooding"]: https://en.wikipedia.org/wiki/SipHash 1507 | [`Iterator`]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html 1508 | [`batching`]: https://docs.rs/itertools/0.6/itertools/trait.Itertools.html#method.batching 1509 | [`dedup`]: https://docs.rs/itertools/0.6/itertools/trait.Itertools.html#method.dedup 1510 | [`group_by`]: https://docs.rs/itertools/0.6/itertools/trait.Itertools.html#method.group_by 1511 | [`mend_slices`]: https://docs.rs/itertools/0.6/itertools/trait.Itertools.html#method.mend_slices 1512 | [`merge`]: https://docs.rs/itertools/0.6/itertools/trait.Itertools.html#method.merge 1513 | [`sorted`]: https://docs.rs/itertools/0.6/itertools/trait.Itertools.html#method.sorted 1514 | [`join`]: https://docs.rs/itertools/0.6/itertools/trait.Itertools.html#method.join 1515 | [`nix`]: https://docs.rs/nix 1516 | [`winapi`]: https://docs.rs/winapi 1517 | [memory-mapped I/O]: https://en.wikipedia.org/wiki/Memory-mapped_file 1518 | [`mmap`]: https://en.wikipedia.org/wiki/mmap 1519 | [`CreateFileMapping`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366537(v=vs.85).aspx 1520 | [`MapViewOfFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366761(v=vs.85).aspx 1521 | [`bitflags!`]: https://docs.rs/bitflags/0.9/bitflags/macro.bitflags.html 1522 | ["endianness"]: https://en.wikipedia.org/wiki/Endianness 1523 | [`RUST_LOG`]: https://docs.rs/env_logger/0.4/env_logger/#filtering-results 1524 | [`error!`]: https://docs.rs/log/0.3/log/macro.error.html 1525 | [`warn!`]: https://docs.rs/log/0.3/log/macro.warn.html 1526 | [`info!`]: https://docs.rs/log/0.3/log/macro.info.html 1527 | [`debug!`]: https://docs.rs/log/0.3/log/macro.debug.html 1528 | [`env_logger`]: https://docs.rs/env_logger 1529 | [hyper]: https://docs.rs/hyper 1530 | [serde.rs]: https://serde.rs/ 1531 | [semver]: http://semver.org/ 1532 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | extern crate skeptic; 2 | 3 | fn main() { 4 | skeptic::generate_doc_tests(&["README.md"]); 5 | } 6 | -------------------------------------------------------------------------------- /examples/bitflags.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate bitflags; 3 | 4 | bitflags! { 5 | struct Flags: u32 { 6 | const FLAG_A = 0b00000001; 7 | const FLAG_B = 0b00000010; 8 | const FLAG_C = 0b00000100; 9 | const FLAG_ABC = FLAG_A.bits 10 | | FLAG_B.bits 11 | | FLAG_C.bits; 12 | } 13 | } 14 | 15 | fn main() { 16 | let e1 = FLAG_A | FLAG_C; 17 | let e2 = FLAG_B | FLAG_C; 18 | assert_eq!((e1 | e2), FLAG_ABC); // union 19 | assert_eq!((e1 & e2), FLAG_C); // intersection 20 | assert_eq!((e1 - e2), FLAG_A); // set difference 21 | assert_eq!(!e2, FLAG_A); // set complement 22 | } 23 | -------------------------------------------------------------------------------- /examples/byteorder.rs: -------------------------------------------------------------------------------- 1 | extern crate byteorder; 2 | 3 | use std::io::Cursor; 4 | use byteorder::{BigEndian, ReadBytesExt}; 5 | use byteorder::{LittleEndian, WriteBytesExt}; 6 | 7 | fn main() { 8 | // Read unsigned 16 bit big-endian integers from a Read type: 9 | let mut rdr = Cursor::new(vec![2, 5, 3, 0]); 10 | // Note that we use type parameters to indicate which kind of byte 11 | // order we want! 12 | assert_eq!(517, rdr.read_u16::().unwrap()); 13 | assert_eq!(768, rdr.read_u16::().unwrap()); 14 | 15 | // Write unsigned 16 bit little-endian integers to a Write type: 16 | let mut wtr = vec![]; 17 | wtr.write_u16::(517).unwrap(); 18 | wtr.write_u16::(768).unwrap(); 19 | assert_eq!(wtr, vec![5, 2, 0, 3]); 20 | } 21 | -------------------------------------------------------------------------------- /examples/chrono.rs: -------------------------------------------------------------------------------- 1 | extern crate chrono; 2 | use chrono::*; 3 | 4 | fn main() { 5 | let local: DateTime = Local::now(); 6 | let utc: DateTime = Utc::now(); 7 | 8 | let dt = Utc.ymd(2014, 11, 28).and_hms(12, 0, 9); 9 | 10 | assert_eq!((dt.year(), dt.month(), dt.day()), (2014, 11, 28)); 11 | assert_eq!((dt.hour(), dt.minute(), dt.second()), (12, 0, 9)); 12 | 13 | assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2014-11-28 12:00:09"); 14 | assert_eq!(dt.format("%a %b %e %T %Y").to_string(), "Fri Nov 28 12:00:09 2014"); 15 | 16 | assert_eq!(format!("{}", dt), "2014-11-28 12:00:09 UTC"); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /examples/clap.rs: -------------------------------------------------------------------------------- 1 | extern crate clap; 2 | use clap::{Arg, App, SubCommand}; 3 | 4 | fn main() { 5 | let app = App::new("My Super Program") 6 | .version("1.0") 7 | .author("Kevin K. ") 8 | .about("Does awesome things") 9 | .arg(Arg::with_name("config") 10 | .short("c") 11 | .long("config") 12 | .value_name("FILE") 13 | .help("Sets a custom config file") 14 | .takes_value(true)) 15 | .arg(Arg::with_name("INPUT") 16 | .help("Sets the input file to use") 17 | .required(true) 18 | .index(1)) 19 | .subcommand(SubCommand::with_name("test") 20 | .about("controls testing features") 21 | .arg(Arg::with_name("debug") 22 | .short("d") 23 | .help("print debug information verbosely"))); 24 | 25 | // Parse the command line arguments 26 | let matches = app.get_matches(); 27 | 28 | let config = matches.value_of("config").unwrap_or("default.conf"); 29 | let input = matches.value_of("INPUT").unwrap(); 30 | 31 | // Handle subcommands 32 | match matches.subcommand() { 33 | ("clone", Some(sub_matches)) => { 34 | if matches.is_present("d") { 35 | // ... 36 | } 37 | }, 38 | ("push", Some(sub_matches)) => {}, 39 | ("commit", Some(sub_matches)) => {}, 40 | _ => {}, 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/encoding_rs.rs: -------------------------------------------------------------------------------- 1 | extern crate encoding_rs; 2 | use encoding_rs::*; 3 | 4 | fn main() { 5 | let expected = "\u{30CF}\u{30ED}\u{30FC}\u{30FB}\u{30EF}\u{30FC}\u{30EB}\u{30C9}"; 6 | let encoded = b"\x83n\x83\x8D\x81[\x81E\x83\x8F\x81[\x83\x8B\x83h"; 7 | 8 | let (decoded, encoding_used, had_errors) = SHIFT_JIS.decode(encoded); 9 | 10 | assert_eq!(&decoded[..], expected); 11 | assert_eq!(encoding_used, SHIFT_JIS); 12 | assert!(!had_errors); 13 | 14 | println!("Decoded result: {}", decoded); 15 | } 16 | -------------------------------------------------------------------------------- /examples/error-chain.rs: -------------------------------------------------------------------------------- 1 | // `error_chain!` can recurse deeply 2 | #![recursion_limit = "1024"] 3 | 4 | #[macro_use] 5 | extern crate error_chain; 6 | 7 | // We'll put our errors in an `errors` module, and other modules in 8 | // this crate will `use errors::*;` to get access to everything 9 | // `error_chain!` creates. 10 | mod errors { 11 | // Create the Error, ErrorKind, ResultExt, and Result types 12 | error_chain! { } 13 | } 14 | 15 | use errors::*; 16 | 17 | fn main() { 18 | if let Err(ref e) = run() { 19 | use ::std::io::Write; 20 | let stderr = &mut ::std::io::stderr(); 21 | let errmsg = "Error writing to stderr"; 22 | 23 | writeln!(stderr, "error: {}", e).expect(errmsg); 24 | 25 | for e in e.iter().skip(1) { 26 | writeln!(stderr, "caused by: {}", e).expect(errmsg); 27 | } 28 | 29 | // The backtrace is not always generated. Try to run this example 30 | // with `RUST_BACKTRACE=1`. 31 | if let Some(backtrace) = e.backtrace() { 32 | writeln!(stderr, "backtrace: {:?}", backtrace).expect(errmsg); 33 | } 34 | 35 | ::std::process::exit(1); 36 | } 37 | } 38 | 39 | // Most functions will return the `Result` type, imported from the 40 | // `errors` module. It is a typedef of the standard `Result` type 41 | // for which the error type is always our own `Error`. 42 | fn run() -> Result<()> { 43 | use std::fs::File; 44 | 45 | // Use chain_err to attach your own context to errors 46 | File::open("my secret file") 47 | .chain_err(|| "unable to open my secret file")?; 48 | 49 | // Use the `bail!` macro to return an error Result, ala `println!` 50 | bail!("giving up"); 51 | } 52 | -------------------------------------------------------------------------------- /examples/flate2.rs: -------------------------------------------------------------------------------- 1 | // Note: this is the same example as tar.rs 2 | 3 | extern crate flate2; 4 | extern crate tar; 5 | 6 | use flate2::read::GzDecoder; 7 | use std::env; 8 | use std::fs::File; 9 | use std::io::{self, BufReader}; 10 | use tar::Archive; 11 | 12 | fn run() -> Result<(), io::Error> { 13 | let mut args = env::args().skip(1); 14 | let tarball = args.next().expect("incorrect argument"); 15 | let outdir = args.next().expect("incorrect argument"); 16 | 17 | let archive = File::open(tarball)?; 18 | let archive = BufReader::new(archive); 19 | let archive = GzDecoder::new(archive)?; 20 | let mut archive = Archive::new(archive); 21 | 22 | archive.unpack(outdir)?; 23 | 24 | Ok(()) 25 | } 26 | 27 | fn main() { run().unwrap() } 28 | -------------------------------------------------------------------------------- /examples/fnv.rs: -------------------------------------------------------------------------------- 1 | extern crate fnv; 2 | 3 | use fnv::FnvHashMap; 4 | 5 | fn main() { 6 | let mut map = FnvHashMap::default(); 7 | map.insert(1, "one"); 8 | map.insert(2, "two"); 9 | map.insert(3, "three"); 10 | 11 | for (number, word) in map.iter() { 12 | println!("Number {}: {}", number, word); 13 | } 14 | 15 | map.remove(&(2)); 16 | println!("The length of HashMap is {}.", map.len()); 17 | println!("The first element is {}.", map.get(&(1)).unwrap()); 18 | } 19 | 20 | -------------------------------------------------------------------------------- /examples/itertools.rs: -------------------------------------------------------------------------------- 1 | extern crate itertools; 2 | 3 | use itertools::{join, max, sorted}; 4 | 5 | fn main(){ 6 | let a = [3, 2, 5, 8, 7]; 7 | 8 | // Combine all iterator elements into one String, 9 | // seperated by *. 10 | println!("{:?}", join(&a, "*")); 11 | // Return the maximum value of the iterable. 12 | println!("{:?}", max(a.iter()).unwrap()); 13 | // Collect all the iterable's elements into a 14 | // sorted vector in ascending order. 15 | println!("{:?}", sorted(a.iter())); 16 | } -------------------------------------------------------------------------------- /examples/lazy_static.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate lazy_static; 3 | 4 | use std::collections::HashMap; 5 | 6 | lazy_static! { 7 | static ref HASHMAP: HashMap = { 8 | let mut m = HashMap::new(); 9 | m.insert(0, "foo"); 10 | m.insert(1, "bar"); 11 | m.insert(2, "baz"); 12 | m 13 | }; 14 | static ref COUNT: usize = HASHMAP.len(); 15 | static ref NUMBER: u32 = times_two(21); 16 | } 17 | 18 | fn times_two(n: u32) -> u32 { n * 2 } 19 | 20 | fn main() { 21 | println!("The map has {} entries.", *COUNT); 22 | println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap()); 23 | println!("A expensive calculation on a static results in: {}.", *NUMBER); 24 | } 25 | -------------------------------------------------------------------------------- /examples/libc.rs: -------------------------------------------------------------------------------- 1 | extern crate libc; 2 | 3 | fn main() { 4 | unsafe { 5 | libc::exit(0); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/log.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate log; 3 | extern crate env_logger; 4 | 5 | use log::LogLevel; 6 | 7 | fn main() { 8 | env_logger::init().unwrap(); 9 | 10 | debug!("this is a debug {}", "message"); 11 | error!("this is printed by default"); 12 | 13 | if log_enabled!(LogLevel::Info) { 14 | let x = 3 * 4; // expensive computation 15 | info!("the answer was: {}", x); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/memmap.rs: -------------------------------------------------------------------------------- 1 | extern crate memmap; 2 | 3 | use memmap::{Mmap, Protection}; 4 | use std::env; 5 | use std::io; 6 | use std::str; 7 | 8 | fn run() -> Result<(), io::Error> { 9 | let mut args = env::args().skip(1); 10 | let input = args.next().expect("incorrect argument"); 11 | 12 | let map = Mmap::open_path(input, Protection::Read)?; 13 | unsafe { 14 | let all_bytes = map.as_slice(); 15 | if let Ok(file_str) = str::from_utf8(all_bytes) { 16 | println!("{}", file_str); 17 | } else { 18 | println!("not utf8"); 19 | } 20 | } 21 | Ok(()) 22 | } 23 | 24 | fn main() { run().unwrap() } 25 | -------------------------------------------------------------------------------- /examples/ndarray.rs: -------------------------------------------------------------------------------- 1 | #[macro_use(s)] 2 | extern crate ndarray; 3 | 4 | use ndarray::{Array3, arr3}; 5 | 6 | fn main() { 7 | // Create a three-dimensional f64 array, initialized with zeros 8 | let mut temperature = Array3::::zeros((3, 4, 5)); 9 | 10 | // Increase the temperature in this location, notice the 11 | // double-brackets indexing `temperature` 12 | temperature[[2, 2, 2]] += 0.5; 13 | 14 | // Create a 3-dimensional matrix, 15 | // 2 submatrices of 2 rows with 3 elements per row, means a shape 16 | // of `[2, 2, 3]`. 17 | let a = arr3(&[[[ 1, 2, 3], // -- 2 rows \_ 18 | [ 4, 5, 6]], // -- / 19 | [[ 7, 8, 9], // \_ 2 submatrices 20 | [10, 11, 12]]]); // / 21 | // 3 columns ..../.../.../ 22 | 23 | // This is a 2 x 2 x 3 array 24 | assert_eq!(a.shape(), &[2, 2, 3]); 25 | 26 | // Let’s create a slice of `a` with 27 | // 28 | // - Both of the submatrices of the greatest dimension: `..` 29 | // - Only the first row in each submatrix: `0..1` 30 | // - Every element in each row: `..` 31 | let b = a.slice(s![.., 0..1, ..]); 32 | 33 | // This is the result of the above slice into `a` 34 | let c = arr3(&[[[ 1, 2, 3]], 35 | [[ 7, 8, 9]]]); 36 | assert_eq!(b, c); 37 | assert_eq!(b.shape(), &[2, 1, 3]); 38 | } 39 | -------------------------------------------------------------------------------- /examples/num.rs: -------------------------------------------------------------------------------- 1 | extern crate num; 2 | 3 | use num::FromPrimitive; 4 | use num::bigint::BigInt; 5 | use num::rational::{Ratio, BigRational}; 6 | 7 | fn approx_sqrt(number: u64, iterations: usize) -> BigRational { 8 | let start: Ratio 9 | = Ratio::from_integer(FromPrimitive::from_u64(number).unwrap()); 10 | 11 | let mut approx = start.clone(); 12 | 13 | for _ in 0..iterations { 14 | approx = (&approx + (&start / &approx)) / 15 | Ratio::from_integer(FromPrimitive::from_u64(2).unwrap()); 16 | } 17 | 18 | approx 19 | } 20 | 21 | fn main() { 22 | println!("{}", approx_sqrt(10, 4)); // prints 4057691201/1283082416 23 | } 24 | -------------------------------------------------------------------------------- /examples/num_cpus.rs: -------------------------------------------------------------------------------- 1 | extern crate threadpool; 2 | extern crate num_cpus; 3 | 4 | use threadpool::ThreadPool; 5 | use std::sync::mpsc::channel; 6 | 7 | fn main() { 8 | // Get the number of cpus on current machine 9 | let n_workers = num_cpus::get(); 10 | let n_jobs = 8; 11 | 12 | // Create the thread pool with amount of workers equal to cores 13 | let pool = ThreadPool::new(n_workers); 14 | 15 | // Create transmitter and receiver channel 16 | let (tx, rx) = channel(); 17 | 18 | for _ in 0..n_jobs { 19 | let tx = tx.clone(); 20 | pool.execute(move || { 21 | tx.send(1).unwrap(); 22 | }); 23 | } 24 | 25 | assert_eq!(rx.iter().take(n_jobs).fold(0, |a, b| a + b), 8); 26 | } 27 | -------------------------------------------------------------------------------- /examples/rand.rs: -------------------------------------------------------------------------------- 1 | extern crate rand; 2 | 3 | use rand::Rng; 4 | 5 | fn main() { 6 | let mut rng = rand::thread_rng(); 7 | if rng.gen() { // random bool 8 | println!("i32: {}, u32: {}", rng.gen::(), rng.gen::()) 9 | } 10 | 11 | let tuple = rand::random::<(f64, char)>(); 12 | println!("{:?}", tuple) 13 | } 14 | -------------------------------------------------------------------------------- /examples/rayon.rs: -------------------------------------------------------------------------------- 1 | extern crate rayon; 2 | 3 | use rayon::prelude::*; 4 | 5 | fn main() { 6 | let mut input = (0..1000).collect::>(); 7 | 8 | // Calculate the sum of squares 9 | let sq_sum: i32 = input.par_iter() 10 | .map(|&i| i * i) 11 | .sum(); 12 | 13 | // Increment each element in parallel 14 | input.par_iter_mut() 15 | .for_each(|p| *p += 1); 16 | 17 | // Parallel quicksort 18 | let mut input = (0..1000).rev().collect::>(); 19 | quick_sort(&mut input); 20 | } 21 | 22 | fn quick_sort(v: &mut [T]) { 23 | if v.len() <= 1 { 24 | return; 25 | } 26 | 27 | let mid = partition(v); 28 | let (lo, hi) = v.split_at_mut(mid); 29 | rayon::join(|| quick_sort(lo), || quick_sort(hi)); 30 | } 31 | 32 | fn partition(v: &mut [T]) -> usize { 33 | let pivot = v.len() - 1; 34 | let mut i = 0; 35 | for j in 0..pivot { 36 | if v[j] <= v[pivot] { 37 | v.swap(i, j); 38 | i += 1; 39 | } 40 | } 41 | v.swap(i, pivot); 42 | i 43 | } 44 | -------------------------------------------------------------------------------- /examples/regex.rs: -------------------------------------------------------------------------------- 1 | extern crate regex; 2 | 3 | use regex::Regex; 4 | 5 | fn main() { 6 | // Find a date 7 | let re = Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap(); 8 | assert!(re.is_match("2014-01-01")); 9 | 10 | // Iterating over capture groups 11 | let re = Regex::new(r"(\d{4})-(\d{2})-(\d{2})").unwrap(); 12 | let text = "2012-03-14, 2013-01-01 and 2014-07-05"; 13 | for cap in re.captures_iter(text) { 14 | println!("Month: {} Day: {} Year: {}", &cap[2], &cap[3], &cap[1]); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /examples/reqwest.rs: -------------------------------------------------------------------------------- 1 | extern crate reqwest; 2 | 3 | use std::collections::HashMap; 4 | use std::io::{BufRead, BufReader}; 5 | 6 | fn main() { 7 | // Make a GET request 8 | let resp = reqwest::get("https://www.rust-lang.org").unwrap(); 9 | assert!(resp.status().is_success()); 10 | 11 | let lines = BufReader::new(resp) 12 | .lines() 13 | .filter_map(|l| l.ok()) 14 | .take(10); 15 | for line in lines { 16 | println!("{}", line); 17 | } 18 | 19 | // Make a POST request 20 | let client = reqwest::Client::new().unwrap(); 21 | let res = client.post("http://httpbin.org/post").unwrap() 22 | .body("the exact body that is sent") 23 | .send(); 24 | 25 | // Convert to/from JSON automatically 26 | let mut map = HashMap::new(); 27 | map.insert("lang", "rust"); 28 | map.insert("body", "json"); 29 | 30 | // This will POST a body of `{"lang":"rust","body":"json"}` 31 | let client = reqwest::Client::new().unwrap(); 32 | let res = client.post("http://httpbin.org/post").unwrap() 33 | .json(&map).unwrap() 34 | .send(); 35 | } 36 | -------------------------------------------------------------------------------- /examples/semver.rs: -------------------------------------------------------------------------------- 1 | extern crate semver; 2 | 3 | use semver::Version; 4 | 5 | fn main() { 6 | // Construct Version objects 7 | assert!(Version::parse("1.2.3") == Ok(Version { 8 | major: 1, 9 | minor: 2, 10 | patch: 3, 11 | pre: vec!(), 12 | build: vec!(), 13 | })); 14 | 15 | // Compare Versions 16 | assert!(Version::parse("1.2.3-alpha") != Version::parse("1.2.3-beta")); 17 | assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.0")); 18 | 19 | // Increment patch number of mutable Version 20 | let mut bugfix_release = Version::parse("1.0.0").unwrap(); 21 | bugfix_release.increment_patch(); 22 | 23 | assert_eq!(Ok(bugfix_release), Version::parse("1.0.1")); 24 | } -------------------------------------------------------------------------------- /examples/serde.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate serde_derive; 3 | extern crate serde_json; 4 | 5 | use serde_json::Value; 6 | 7 | #[derive(Serialize, Deserialize, Debug)] 8 | struct Contact { 9 | name: String, 10 | age: u32, 11 | } 12 | 13 | fn main() { 14 | let contact = Contact { 15 | name: "Brian".to_string(), 16 | age: 21, 17 | }; 18 | 19 | // Serialize data structures to strings in JSON format 20 | let contact: String = serde_json::to_string(&contact).unwrap(); 21 | println!("{}", contact); 22 | 23 | // Deserialize data structures from JSON strings 24 | let contact: Contact = serde_json::from_str(&contact).unwrap(); 25 | println!("{:?}", contact); 26 | 27 | // Convert to arbitrary JSON `Value` type 28 | let contact: Value = serde_json::to_value(&contact).unwrap(); 29 | println!("{:?}", contact); 30 | } 31 | -------------------------------------------------------------------------------- /examples/serde_json.rs: -------------------------------------------------------------------------------- 1 | extern crate serde_json; 2 | 3 | use serde_json::Value; 4 | 5 | fn main() { 6 | // Some JSON input data as a &str. Maybe this comes from the user. 7 | let data = r#"{ 8 | "name": "John Doe", 9 | "age": 43, 10 | "phones": [ 11 | "+44 1234567", 12 | "+44 2345678" 13 | ] 14 | }"#; 15 | 16 | // Parse the string of data into serde_json::Value. 17 | let v: Value = serde_json::from_str(data).unwrap(); 18 | 19 | // Access parts of the data by indexing with square brackets. 20 | println!("Please call {} at the number {}", v["name"], v["phones"][0]); 21 | } 22 | -------------------------------------------------------------------------------- /examples/tar.rs: -------------------------------------------------------------------------------- 1 | // Note: this is the same example as tar.rs 2 | 3 | extern crate flate2; 4 | extern crate tar; 5 | 6 | use flate2::read::GzDecoder; 7 | use std::env; 8 | use std::fs::File; 9 | use std::io::{self, BufReader}; 10 | use tar::Archive; 11 | 12 | fn run() -> Result<(), io::Error> { 13 | let mut args = env::args().skip(1); 14 | let tarball = args.next().expect("incorrect argument"); 15 | let outdir = args.next().expect("incorrect argument"); 16 | 17 | let archive = File::open(tarball)?; 18 | let archive = BufReader::new(archive); 19 | let archive = GzDecoder::new(archive)?; 20 | let mut archive = Archive::new(archive); 21 | 22 | archive.unpack(outdir)?; 23 | 24 | Ok(()) 25 | } 26 | 27 | fn main() { run().unwrap() } 28 | -------------------------------------------------------------------------------- /examples/tempdir.rs: -------------------------------------------------------------------------------- 1 | extern crate tempdir; 2 | 3 | use std::fs::File; 4 | use std::io::Write; 5 | use tempdir::TempDir; 6 | 7 | fn main() { 8 | // Create a directory inside of `std::env::temp_dir()`, named with 9 | // the prefix "example". 10 | let tmp_dir = TempDir::new("example").expect("create temp dir"); 11 | let file_path = tmp_dir.path().join("my-temporary-note.txt"); 12 | let mut tmp_file = File::create(file_path).expect("create temp file"); 13 | writeln!(tmp_file, "Brian was here. Briefly.").expect("write temp file"); 14 | 15 | // By closing the `TempDir` explicitly, we can check that it has 16 | // been deleted successfully. If we don't close it explicitly, 17 | // the directory will still be deleted when `tmp_dir` goes out 18 | // of scope, but we won't know whether deleting the directory 19 | // succeeded. 20 | drop(tmp_file); 21 | tmp_dir.close().expect("delete temp dir"); 22 | } 23 | -------------------------------------------------------------------------------- /examples/threadpool.rs: -------------------------------------------------------------------------------- 1 | extern crate threadpool; 2 | extern crate num_cpus; 3 | 4 | use threadpool::ThreadPool; 5 | use std::sync::mpsc::channel; 6 | 7 | fn main() { 8 | // Get the number of cpus on current machine 9 | let n_workers = num_cpus::get(); 10 | let n_jobs = 8; 11 | 12 | // Create the thread pool with amount of workers equal to cores 13 | let pool = ThreadPool::new(n_workers); 14 | 15 | // Create transmitter and receiver channel 16 | let (tx, rx) = channel(); 17 | 18 | // For each job grab a free worker from the pool and execute 19 | for _ in 0..n_jobs { 20 | let tx = tx.clone(); 21 | pool.execute(move || { 22 | tx.send(1).unwrap(); 23 | }); 24 | } 25 | 26 | assert_eq!(rx.iter().take(n_jobs).fold(0, |a, b| a + b), 8); 27 | } 28 | -------------------------------------------------------------------------------- /examples/toml.rs: -------------------------------------------------------------------------------- 1 | extern crate toml; 2 | 3 | use toml::Value; 4 | 5 | fn main() { 6 | let toml = r#" 7 | [test] 8 | foo = "bar" 9 | "#; 10 | 11 | let value = toml.parse::().unwrap(); 12 | println!("{:?}", value); 13 | } 14 | -------------------------------------------------------------------------------- /examples/url.rs: -------------------------------------------------------------------------------- 1 | extern crate url; 2 | 3 | use url::{Url, Host}; 4 | 5 | fn main() { 6 | let issue_list_url = Url::parse( 7 | "https://github.com/rust-lang/rust/issues?labels=E-easy&state=open" 8 | ).unwrap(); 9 | 10 | assert!(issue_list_url.scheme() == "https"); 11 | assert!(issue_list_url.username() == ""); 12 | assert!(issue_list_url.password() == None); 13 | assert!(issue_list_url.host_str() == Some("github.com")); 14 | assert!(issue_list_url.host() == Some(Host::Domain("github.com"))); 15 | assert!(issue_list_url.port() == None); 16 | assert!(issue_list_url.path() == "/rust-lang/rust/issues"); 17 | assert!(issue_list_url.path_segments().map(|c| c.collect::>()) == 18 | Some(vec!["rust-lang", "rust", "issues"])); 19 | assert!(issue_list_url.query() == Some("labels=E-easy&state=open")); 20 | assert!(issue_list_url.fragment() == None); 21 | assert!(!issue_list_url.cannot_be_a_base()); 22 | } 23 | -------------------------------------------------------------------------------- /examples/walkdir.rs: -------------------------------------------------------------------------------- 1 | extern crate walkdir; 2 | 3 | use walkdir::{WalkDir, Error}; 4 | 5 | fn run() -> Result<(), Error> { 6 | let wd = WalkDir::new("."); 7 | 8 | for entry in wd { 9 | let entry = entry?; 10 | println!("{}", entry.path().display()); 11 | } 12 | 13 | Ok(()) 14 | } 15 | 16 | fn main() { run().unwrap(); } 17 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | 2 | // Extended std prelude. 3 | 4 | // Re-export all modules from std to allow use stdx::*; 5 | pub use std::*; 6 | 7 | // Export the most commonly used parts of std that are not in the std prelude. 8 | 9 | pub use std::any::{Any, TypeId}; 10 | pub use std::borrow::{Borrow, BorrowMut, ToOwned, Cow}; 11 | pub use std::cell::{Cell, RefCell}; 12 | pub use std::cmp::{min, max}; 13 | pub use std::clone::Clone; 14 | pub use std::collections::{HashMap, HashSet, VecDeque}; 15 | pub use std::default::Default; 16 | pub use std::error::Error; 17 | pub use std::ffi::OsString; 18 | pub use std::fmt::{Debug, Display}; 19 | pub use std::fs::File; 20 | pub use std::hash::Hash; 21 | pub use std::io::{BufRead, Read, Seek, SeekFrom, Write}; 22 | pub use std::iter::{FromIterator, IntoIterator, Iterator}; 23 | pub use std::ops::{Deref, DerefMut}; 24 | pub use std::path::{Path, PathBuf}; 25 | pub use std::rc::Rc; 26 | pub use std::str::FromStr; 27 | pub use std::sync::{Arc, Mutex, RwLock}; 28 | pub use std::time::{Duration}; 29 | 30 | // Re-export included crates and the most important types. 31 | 32 | pub extern crate bitflags; 33 | pub extern crate byteorder; 34 | pub extern crate chrono; 35 | pub extern crate clap; 36 | pub extern crate error_chain; 37 | pub extern crate flate2; 38 | pub extern crate fnv; 39 | pub extern crate itertools; 40 | pub extern crate lazy_static; 41 | pub extern crate libc; 42 | pub extern crate log; 43 | pub extern crate memmap; 44 | pub extern crate ndarray; 45 | pub extern crate num; 46 | pub extern crate num_cpus; 47 | pub extern crate rand; 48 | pub extern crate rayon; 49 | pub extern crate regex; 50 | pub extern crate reqwest; 51 | pub extern crate semver; 52 | 53 | pub extern crate serde; 54 | pub use serde::{Deserialize, Serialize}; 55 | pub use serde::de::DeserializeOwned; 56 | 57 | pub extern crate serde_json; 58 | pub extern crate tar; 59 | pub extern crate tempdir; 60 | pub extern crate threadpool; 61 | pub extern crate toml; 62 | pub extern crate url; 63 | pub extern crate walkdir; 64 | 65 | // Supplemental dependencies. 66 | 67 | pub extern crate env_logger; 68 | -------------------------------------------------------------------------------- /tests/skeptic.rs: -------------------------------------------------------------------------------- 1 | include!(concat!(env!("OUT_DIR"), "/skeptic-tests.rs")); 2 | --------------------------------------------------------------------------------