Skip to content

Commit e38739b

Browse files
committed
Convert rust_log.cpp to Rust, closes #8703
1 parent ed422b8 commit e38739b

File tree

6 files changed

+285
-190
lines changed

6 files changed

+285
-190
lines changed

mk/rt.mk

-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ RUNTIME_CXXS_$(1)_$(2) := \
7676
rt/rust_upcall.cpp \
7777
rt/rust_uv.cpp \
7878
rt/rust_crate_map.cpp \
79-
rt/rust_log.cpp \
8079
rt/isaac/randport.cpp \
8180
rt/miniz.cpp \
8281
rt/memory_region.cpp \

src/libstd/rt/logging.rs

+248-15
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,159 @@
77
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
10-
10+
use cast::transmute;
1111
use either::*;
12-
use libc;
12+
use libc::{c_void, uintptr_t, c_char, exit, STDERR_FILENO};
13+
use option::{Some, None};
14+
use rt::util::dumb_println;
1315
use str::StrSlice;
16+
use str::raw::from_c_str;
17+
use u32;
18+
use unstable::raw::Closure;
19+
use vec::ImmutableVector;
20+
21+
22+
struct LogDirective {
23+
name: ~str,
24+
level: u32
25+
}
26+
27+
// This is the Rust representation of the mod_entry struct in src/rt/rust_crate_map.h
28+
struct ModEntry{
29+
name: *c_char,
30+
log_level: *mut u32
31+
}
32+
33+
static MAX_LOG_DIRECTIVES: u32 = 255;
34+
static MAX_LOG_LEVEL: u32 = 255;
35+
static DEFAULT_LOG_LEVEL: u32 = 1;
36+
37+
fn iter_crate_map(map: *u8, f: &fn(*mut ModEntry)) {
38+
unsafe {
39+
let closure : Closure = transmute(f);
40+
let code = transmute(closure.code);
41+
let env = transmute(closure.env);
42+
rust_iter_crate_map(transmute(map), iter_cb, code, env);
43+
}
44+
45+
extern fn iter_cb(code: *c_void, env: *c_void, entry: *ModEntry){
46+
unsafe {
47+
let closure: Closure = Closure {
48+
code: transmute(code),
49+
env: transmute(env),
50+
};
51+
let closure: &fn(*ModEntry) = transmute(closure);
52+
return closure(entry);
53+
}
54+
}
55+
extern {
56+
#[cfg(not(stage0))]
57+
#[rust_stack]
58+
fn rust_iter_crate_map(map: *c_void,
59+
f: extern "C" fn(*c_void, *c_void, entry: *ModEntry),
60+
code: *c_void,
61+
data: *c_void);
62+
63+
#[cfg(stage0)]
64+
#[rust_stack]
65+
fn rust_iter_crate_map(map: *c_void,
66+
f: *u8,
67+
code: *c_void,
68+
data: *c_void);
69+
}
70+
}
71+
72+
/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1")
73+
/// and return a vector with log directives.
74+
/// Valid log levels are 0-255, with the most likely ones being 0-3 (defined in std::).
75+
fn parse_logging_spec(spec: ~str) -> ~[LogDirective]{
76+
let mut dirs = ~[];
77+
for s in spec.split_iter(',') {
78+
let parts: ~[&str] = s.split_iter('=').collect();
79+
let mut loglevel;
80+
match parts.len() {
81+
1 => loglevel = MAX_LOG_LEVEL,
82+
2 => {
83+
let num = u32::from_str(parts[1]);
84+
match (num) {
85+
Some(num) => {
86+
if num < MAX_LOG_LEVEL {
87+
loglevel = num;
88+
} else {
89+
loglevel = MAX_LOG_LEVEL;
90+
}
91+
}
92+
_ => {
93+
dumb_println(fmt!("warning: invalid logging spec \
94+
'%s', ignoring it", s));
95+
loop;
96+
}
97+
}
98+
if loglevel > MAX_LOG_LEVEL { loglevel = MAX_LOG_LEVEL}
99+
},
100+
_ => {
101+
dumb_println(fmt!("warning: invalid logging spec '%s',\
102+
ignoring it", s));
103+
loop;
104+
}
105+
}
106+
let dir = LogDirective {name: parts[0].to_owned(), level: loglevel};
107+
dirs.push(dir);
108+
}
109+
return dirs;
110+
}
111+
112+
/// Set the log level of an entry in the crate map depending on the vector
113+
/// of log directives
114+
fn update_entry(dirs: &[LogDirective], entry: *mut ModEntry) -> u32 {
115+
let mut new_lvl: u32 = DEFAULT_LOG_LEVEL;
116+
let mut longest_match = 0;
117+
unsafe {
118+
for dir in dirs.iter() {
119+
let name = from_c_str((*entry).name);
120+
if name.starts_with(dir.name) && dir.name.len() > longest_match {
121+
longest_match = dir.name.len();
122+
new_lvl = dir.level;
123+
}
124+
}
125+
*(*entry).log_level = new_lvl;
126+
}
127+
if longest_match > 0 { return 1; } else { return 0; }
128+
}
129+
130+
#[fixed_stack_segment] #[inline(never)]
131+
/// Set log level for every entry in crate_map according to the sepecification
132+
/// in settings
133+
fn update_log_settings(crate_map: *u8, settings: ~str) {
134+
let mut dirs = ~[];
135+
if settings.len() > 0 {
136+
if settings == ~"::help" || settings == ~"?" {
137+
dumb_println("\nCrate log map:\n");
138+
do iter_crate_map(crate_map) |entry: *mut ModEntry| {
139+
unsafe {
140+
dumb_println(" "+from_c_str((*entry).name));
141+
}
142+
}
143+
unsafe {
144+
exit(1);
145+
}
146+
}
147+
dirs = parse_logging_spec(settings);
148+
}
149+
150+
let mut n_matches: u32 = 0;
151+
do iter_crate_map(crate_map) |entry: *mut ModEntry| {
152+
let m = update_entry(dirs, entry);
153+
n_matches += m;
154+
}
155+
156+
if n_matches < (dirs.len() as u32) {
157+
dumb_println(fmt!("warning: got %u RUST_LOG specs but only matched %u of them.\n\
158+
You may have mistyped a RUST_LOG spec.\n\
159+
Use RUST_LOG=::help to see the list of crates and modules.\n",
160+
dirs.len() as uint, n_matches as uint));
161+
}
162+
}
14163

15164
pub trait Logger {
16165
fn log(&mut self, msg: Either<~str, &'static str>);
@@ -47,34 +196,26 @@ impl Logger for StdErrLogger {
47196
};
48197

49198
fn print(s: &str) {
50-
let dbg = ::libc::STDERR_FILENO as ::io::fd_t;
199+
let dbg = STDERR_FILENO as ::io::fd_t;
51200
dbg.write_str(s);
52201
dbg.write_str("\n");
53202
dbg.flush();
54203
}
55204
}
56205
}
57-
58206
/// Configure logging by traversing the crate map and setting the
59207
/// per-module global logging flags based on the logging spec
60208
#[fixed_stack_segment] #[inline(never)]
61209
pub fn init(crate_map: *u8) {
62-
use c_str::ToCStr;
63210
use os;
64-
use ptr;
65-
use option::{Some, None};
66211

67212
let log_spec = os::getenv("RUST_LOG");
68213
match log_spec {
69214
Some(spec) => {
70-
do spec.with_c_str |buf| {
71-
unsafe { rust_update_log_settings(crate_map, buf) }
72-
}
215+
update_log_settings(crate_map, spec);
73216
}
74217
None => {
75-
unsafe {
76-
rust_update_log_settings(crate_map, ptr::null());
77-
}
218+
update_log_settings(crate_map, ~"");
78219
}
79220
}
80221
}
@@ -89,9 +230,101 @@ pub fn console_off() { unsafe { rust_log_console_off() } }
89230
fn should_log_console() -> bool { unsafe { rust_should_log_console() != 0 } }
90231

91232
extern {
92-
fn rust_update_log_settings(crate_map: *u8, settings: *libc::c_char);
93233
fn rust_log_console_on();
94234
fn rust_log_console_off();
95-
fn rust_should_log_console() -> libc::uintptr_t;
235+
fn rust_should_log_console() -> uintptr_t;
236+
}
237+
238+
// Tests for parse_logging_spec()
239+
#[test]
240+
fn parse_logging_spec_valid() {
241+
let dirs: ~[LogDirective] = parse_logging_spec(~"crate1::mod1=1,crate1::mod2,crate2=4");
242+
assert_eq!(dirs.len(), 3);
243+
assert!(dirs[0].name == ~"crate1::mod1");
244+
assert_eq!(dirs[0].level, 1);
245+
246+
assert!(dirs[1].name == ~"crate1::mod2");
247+
assert_eq!(dirs[1].level, MAX_LOG_LEVEL);
248+
249+
assert!(dirs[2].name == ~"crate2");
250+
assert_eq!(dirs[2].level, 4);
251+
}
252+
253+
#[test]
254+
fn parse_logging_spec_invalid_crate() {
255+
// test parse_logging_spec with multiple = in specification
256+
let dirs: ~[LogDirective] = parse_logging_spec(~"crate1::mod1=1=2,crate2=4");
257+
assert_eq!(dirs.len(), 1);
258+
assert!(dirs[0].name == ~"crate2");
259+
assert_eq!(dirs[0].level, 4);
260+
}
261+
262+
#[test]
263+
fn parse_logging_spec_invalid_log_level() {
264+
// test parse_logging_spec with 'noNumber' as log level
265+
let dirs: ~[LogDirective] = parse_logging_spec(~"crate1::mod1=noNumber,crate2=4");
266+
assert_eq!(dirs.len(), 1);
267+
assert!(dirs[0].name == ~"crate2");
268+
assert_eq!(dirs[0].level, 4);
269+
}
270+
271+
// Tests for update_entry
272+
#[test]
273+
fn update_entry_match_full_path() {
274+
use c_str::ToCStr;
275+
let dirs = ~[LogDirective {name: ~"crate1::mod1", level: 2 },
276+
LogDirective {name: ~"crate2", level: 3}];
277+
unsafe {
278+
do "crate1::mod1".to_c_str().with_ref |ptr| {
279+
let entry= &ModEntry {name: ptr, log_level: &mut 0};
280+
let m = update_entry(dirs, transmute(entry));
281+
assert!(*entry.log_level == 2);
282+
assert!(m == 1);
283+
}
284+
}
96285
}
97286
287+
#[test]
288+
fn update_entry_no_match() {
289+
use c_str::ToCStr;
290+
let dirs = ~[LogDirective {name: ~"crate1::mod1", level: 2 },
291+
LogDirective {name: ~"crate2", level: 3}];
292+
unsafe {
293+
do "crate3::mod1".to_c_str().with_ref |ptr| {
294+
let entry= &ModEntry {name: ptr, log_level: &mut 0};
295+
let m = update_entry(dirs, transmute(entry));
296+
assert!(*entry.log_level == DEFAULT_LOG_LEVEL);
297+
assert!(m == 0);
298+
}
299+
}
300+
}
301+
302+
#[test]
303+
fn update_entry_match_beginning() {
304+
use c_str::ToCStr;
305+
let dirs = ~[LogDirective {name: ~"crate1::mod1", level: 2 },
306+
LogDirective {name: ~"crate2", level: 3}];
307+
unsafe {
308+
do "crate2::mod1".to_c_str().with_ref |ptr| {
309+
let entry= &ModEntry {name: ptr, log_level: &mut 0};
310+
let m = update_entry(dirs, transmute(entry));
311+
assert!(*entry.log_level == 3);
312+
assert!(m == 1);
313+
}
314+
}
315+
}
316+
317+
#[test]
318+
fn update_entry_match_beginning_longest_match() {
319+
use c_str::ToCStr;
320+
let dirs = ~[LogDirective {name: ~"crate1::mod1", level: 2 },
321+
LogDirective {name: ~"crate2", level: 3}, LogDirective {name: ~"crate2::mod", level: 4}];
322+
unsafe {
323+
do "crate2::mod1".to_c_str().with_ref |ptr| {
324+
let entry = &ModEntry {name: ptr, log_level: &mut 0};
325+
let m = update_entry(dirs, transmute(entry));
326+
assert!(*entry.log_level == 4);
327+
assert!(m == 1);
328+
}
329+
}
330+
}

src/rt/rust_crate_map.cpp

+27-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -12,36 +12,52 @@
1212
#include <set>
1313

1414
void iter_module_map(const mod_entry* map,
15-
void (*fn)(const mod_entry* entry, void *cookie),
16-
void *cookie) {
15+
void (*fn)(void* fptr, void* env, const mod_entry *entry),
16+
void* fptr,
17+
void* env
18+
) {
1719
for (const mod_entry* cur = map; cur->name; cur++) {
18-
fn(cur, cookie);
20+
fn(fptr, env, cur);
1921
}
2022
}
2123

2224
void iter_crate_map(const cratemap* map,
23-
void (*fn)(const mod_entry* map, void *cookie),
24-
void *cookie,
25+
void (*fn)(void* fptr, void* env, const mod_entry *entry),
26+
void *fptr,
27+
void *env,
2528
std::set<const cratemap*>& visited) {
2629
if (visited.find(map) == visited.end()) {
2730
// Mark this crate visited
2831
visited.insert(map);
2932
// First iterate this crate
30-
iter_module_map(map->entries(), fn, cookie);
33+
iter_module_map(map->entries(), fn, fptr, env);
3134
// Then recurse on linked crates
3235
for (cratemap::iterator i = map->begin(),
3336
e = map->end(); i != e; ++i) {
34-
iter_crate_map(*i, fn, cookie, visited);
37+
iter_crate_map(*i, fn, fptr, env, visited);
3538
}
3639
}
3740
}
3841

3942
void iter_crate_map(const cratemap* map,
40-
void (*fn)(const mod_entry* map, void *cookie),
41-
void *cookie) {
43+
void (*fn)(void* fptr, void* env, const mod_entry *entry),
44+
void *fptr,
45+
void *env
46+
) {
4247
std::set<const cratemap*> visited;
43-
iter_crate_map(map, fn, cookie, visited);
48+
iter_crate_map(map, fn, fptr, env, visited);
4449
}
50+
51+
extern "C" CDECL void
52+
rust_iter_crate_map(const cratemap* map,
53+
void (*fn)(void* fptr, void* env, const mod_entry *entry),
54+
void *fptr,
55+
void *env
56+
) {
57+
return iter_crate_map(map, fn, fptr, env);
58+
}
59+
60+
4561
//
4662
// Local Variables:
4763
// mode: C++

0 commit comments

Comments
 (0)