mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-26 23:45:30 +00:00
0cdde6e5e0
This commits adds an associated type to the `FromStr` trait representing an error payload for parses which do not succeed. The previous return value, `Option<Self>` did not allow for this form of payload. After the associated type was added, the following attributes were applied: * `FromStr` is now stable * `FromStr::Err` is now stable * `FromStr::from_str` is now stable * `StrExt::parse` is now stable * `FromStr for bool` is now stable * `FromStr for $float` is now stable * `FromStr for $integral` is now stable * Errors returned from stable `FromStr` implementations are stable * Errors implement `Display` and `Error` (both impl blocks being `#[stable]`) Closes #15138
189 lines
6.9 KiB
Rust
189 lines
6.9 KiB
Rust
// 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.
|
|
|
|
use std::ascii::AsciiExt;
|
|
use std::cmp;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct LogDirective {
|
|
pub name: Option<String>,
|
|
pub level: u32,
|
|
}
|
|
|
|
pub static LOG_LEVEL_NAMES: [&'static str; 4] = ["ERROR", "WARN", "INFO",
|
|
"DEBUG"];
|
|
|
|
/// Parse an individual log level that is either a number or a symbolic log level
|
|
fn parse_log_level(level: &str) -> Option<u32> {
|
|
level.parse::<u32>().ok().or_else(|| {
|
|
let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level));
|
|
pos.map(|p| p as u32 + 1)
|
|
}).map(|p| cmp::min(p, ::MAX_LOG_LEVEL))
|
|
}
|
|
|
|
/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo")
|
|
/// and return a vector with log directives.
|
|
///
|
|
/// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in
|
|
/// std::). Also supports string log levels of error, warn, info, and debug
|
|
pub fn parse_logging_spec(spec: &str) -> (Vec<LogDirective>, Option<String>) {
|
|
let mut dirs = Vec::new();
|
|
|
|
let mut parts = spec.split('/');
|
|
let mods = parts.next();
|
|
let filter = parts.next();
|
|
if parts.next().is_some() {
|
|
println!("warning: invalid logging spec '{}', \
|
|
ignoring it (too many '/'s)", spec);
|
|
return (dirs, None);
|
|
}
|
|
mods.map(|m| { for s in m.split(',') {
|
|
if s.len() == 0 { continue }
|
|
let mut parts = s.split('=');
|
|
let (log_level, name) = match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
|
|
(Some(part0), None, None) => {
|
|
// if the single argument is a log-level string or number,
|
|
// treat that as a global fallback
|
|
match parse_log_level(part0) {
|
|
Some(num) => (num, None),
|
|
None => (::MAX_LOG_LEVEL, Some(part0)),
|
|
}
|
|
}
|
|
(Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)),
|
|
(Some(part0), Some(part1), None) => {
|
|
match parse_log_level(part1) {
|
|
Some(num) => (num, Some(part0)),
|
|
_ => {
|
|
println!("warning: invalid logging spec '{}', \
|
|
ignoring it", part1);
|
|
continue
|
|
}
|
|
}
|
|
},
|
|
_ => {
|
|
println!("warning: invalid logging spec '{}', \
|
|
ignoring it", s);
|
|
continue
|
|
}
|
|
};
|
|
dirs.push(LogDirective {
|
|
name: name.map(|s| s.to_string()),
|
|
level: log_level,
|
|
});
|
|
}});
|
|
|
|
(dirs, filter.map(|s| s.to_string()))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::parse_logging_spec;
|
|
|
|
#[test]
|
|
fn parse_logging_spec_valid() {
|
|
let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4");
|
|
assert_eq!(dirs.len(), 3);
|
|
assert_eq!(dirs[0].name, Some("crate1::mod1".to_string()));
|
|
assert_eq!(dirs[0].level, 1);
|
|
|
|
assert_eq!(dirs[1].name, Some("crate1::mod2".to_string()));
|
|
assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL);
|
|
|
|
assert_eq!(dirs[2].name, Some("crate2".to_string()));
|
|
assert_eq!(dirs[2].level, 4);
|
|
assert!(filter.is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn parse_logging_spec_invalid_crate() {
|
|
// test parse_logging_spec with multiple = in specification
|
|
let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4");
|
|
assert_eq!(dirs.len(), 1);
|
|
assert_eq!(dirs[0].name, Some("crate2".to_string()));
|
|
assert_eq!(dirs[0].level, 4);
|
|
assert!(filter.is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn parse_logging_spec_invalid_log_level() {
|
|
// test parse_logging_spec with 'noNumber' as log level
|
|
let (dirs, filter) = parse_logging_spec("crate1::mod1=noNumber,crate2=4");
|
|
assert_eq!(dirs.len(), 1);
|
|
assert_eq!(dirs[0].name, Some("crate2".to_string()));
|
|
assert_eq!(dirs[0].level, 4);
|
|
assert!(filter.is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn parse_logging_spec_string_log_level() {
|
|
// test parse_logging_spec with 'warn' as log level
|
|
let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=warn");
|
|
assert_eq!(dirs.len(), 1);
|
|
assert_eq!(dirs[0].name, Some("crate2".to_string()));
|
|
assert_eq!(dirs[0].level, ::WARN);
|
|
assert!(filter.is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn parse_logging_spec_empty_log_level() {
|
|
// test parse_logging_spec with '' as log level
|
|
let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=");
|
|
assert_eq!(dirs.len(), 1);
|
|
assert_eq!(dirs[0].name, Some("crate2".to_string()));
|
|
assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL);
|
|
assert!(filter.is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn parse_logging_spec_global() {
|
|
// test parse_logging_spec with no crate
|
|
let (dirs, filter) = parse_logging_spec("warn,crate2=4");
|
|
assert_eq!(dirs.len(), 2);
|
|
assert_eq!(dirs[0].name, None);
|
|
assert_eq!(dirs[0].level, 2);
|
|
assert_eq!(dirs[1].name, Some("crate2".to_string()));
|
|
assert_eq!(dirs[1].level, 4);
|
|
assert!(filter.is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn parse_logging_spec_valid_filter() {
|
|
let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4/abc");
|
|
assert_eq!(dirs.len(), 3);
|
|
assert_eq!(dirs[0].name, Some("crate1::mod1".to_string()));
|
|
assert_eq!(dirs[0].level, 1);
|
|
|
|
assert_eq!(dirs[1].name, Some("crate1::mod2".to_string()));
|
|
assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL);
|
|
|
|
assert_eq!(dirs[2].name, Some("crate2".to_string()));
|
|
assert_eq!(dirs[2].level, 4);
|
|
assert!(filter.is_some() && filter.unwrap().to_string() == "abc");
|
|
}
|
|
|
|
#[test]
|
|
fn parse_logging_spec_invalid_crate_filter() {
|
|
let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4/a.c");
|
|
assert_eq!(dirs.len(), 1);
|
|
assert_eq!(dirs[0].name, Some("crate2".to_string()));
|
|
assert_eq!(dirs[0].level, 4);
|
|
assert!(filter.is_some() && filter.unwrap().to_string() == "a.c");
|
|
}
|
|
|
|
#[test]
|
|
fn parse_logging_spec_empty_with_filter() {
|
|
let (dirs, filter) = parse_logging_spec("crate1/a*c");
|
|
assert_eq!(dirs.len(), 1);
|
|
assert_eq!(dirs[0].name, Some("crate1".to_string()));
|
|
assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL);
|
|
assert!(filter.is_some() && filter.unwrap().to_string() == "a*c");
|
|
}
|
|
}
|