From b1858447d36943f96fd4fb940e878b9db7bf3d22 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Tue, 9 May 2017 12:54:43 -0400 Subject: [PATCH 1/5] fix confusion about parts required for float formatting The documentation for flt2dec doesn't match up with the actual implementation, so fix the documentation to align with reality. Presumably due to the mismatch, the formatting code for floats in std::fmt can use correspondingly shorter arrays in some places, so fix those places up as well. Fixes #41304. --- src/libcore/fmt/float.rs | 8 ++++---- src/libcore/num/flt2dec/mod.rs | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs index 87def375b202b..4825c2aa13264 100644 --- a/src/libcore/fmt/float.rs +++ b/src/libcore/fmt/float.rs @@ -21,7 +21,7 @@ fn float_to_decimal_common_exact(fmt: &mut Formatter, num: &T, { unsafe { let mut buf: [u8; 1024] = mem::uninitialized(); // enough for f32 and f64 - let mut parts: [flt2dec::Part; 5] = mem::uninitialized(); + let mut parts: [flt2dec::Part; 4] = mem::uninitialized(); let formatted = flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact, *num, sign, precision, false, &mut buf, &mut parts); @@ -39,7 +39,7 @@ fn float_to_decimal_common_shortest(fmt: &mut Formatter, unsafe { // enough for f32 and f64 let mut buf: [u8; flt2dec::MAX_SIG_DIGITS] = mem::uninitialized(); - let mut parts: [flt2dec::Part; 5] = mem::uninitialized(); + let mut parts: [flt2dec::Part; 4] = mem::uninitialized(); let formatted = flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest, *num, sign, 0, false, &mut buf, &mut parts); fmt.pad_formatted_parts(&formatted) @@ -75,7 +75,7 @@ fn float_to_exponential_common_exact(fmt: &mut Formatter, num: &T, { unsafe { let mut buf: [u8; 1024] = mem::uninitialized(); // enough for f32 and f64 - let mut parts: [flt2dec::Part; 7] = mem::uninitialized(); + let mut parts: [flt2dec::Part; 6] = mem::uninitialized(); let formatted = flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact, *num, sign, precision, upper, &mut buf, &mut parts); @@ -94,7 +94,7 @@ fn float_to_exponential_common_shortest(fmt: &mut Formatter, unsafe { // enough for f32 and f64 let mut buf: [u8; flt2dec::MAX_SIG_DIGITS] = mem::uninitialized(); - let mut parts: [flt2dec::Part; 7] = mem::uninitialized(); + let mut parts: [flt2dec::Part; 6] = mem::uninitialized(); let formatted = flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest, *num, sign, (0, 0), upper, &mut buf, &mut parts); diff --git a/src/libcore/num/flt2dec/mod.rs b/src/libcore/num/flt2dec/mod.rs index 5123e42df61ca..74b9e7bf37d51 100644 --- a/src/libcore/num/flt2dec/mod.rs +++ b/src/libcore/num/flt2dec/mod.rs @@ -410,8 +410,8 @@ fn determine_sign(sign: Sign, decoded: &FullDecoded, negative: bool) -> &'static /// it will only print given digits and nothing else. /// /// The byte buffer should be at least `MAX_SIG_DIGITS` bytes long. -/// There should be at least 5 parts available, due to the worst case like -/// `[+][0.][0000][45][0000]` with `frac_digits = 10`. +/// There should be at least 4 parts available, due to the worst case like +/// `[+][0.][0000][2][0000]` with `frac_digits = 10`. pub fn to_shortest_str<'a, T, F>(mut format_shortest: F, v: T, sign: Sign, frac_digits: usize, _upper: bool, buf: &'a mut [u8], parts: &'a mut [Part<'a>]) -> Formatted<'a> @@ -465,8 +465,8 @@ pub fn to_shortest_str<'a, T, F>(mut format_shortest: F, v: T, /// cannot be in this range, avoiding any confusion. /// /// The byte buffer should be at least `MAX_SIG_DIGITS` bytes long. -/// There should be at least 7 parts available, due to the worst case like -/// `[+][1][.][2345][e][-][67]`. +/// There should be at least 6 parts available, due to the worst case like +/// `[+][1][.][2345][e][-][6]`. pub fn to_shortest_exp_str<'a, T, F>(mut format_shortest: F, v: T, sign: Sign, dec_bounds: (i16, i16), upper: bool, buf: &'a mut [u8], parts: &'a mut [Part<'a>]) -> Formatted<'a> @@ -544,8 +544,8 @@ fn estimate_max_buf_len(exp: i16) -> usize { /// The byte buffer should be at least `ndigits` bytes long unless `ndigits` is /// so large that only the fixed number of digits will be ever written. /// (The tipping point for `f64` is about 800, so 1000 bytes should be enough.) -/// There should be at least 7 parts available, due to the worst case like -/// `[+][1][.][2345][e][-][67]`. +/// There should be at least 6 parts available, due to the worst case like +/// `[+][1][.][2345][e][-][6]`. pub fn to_exact_exp_str<'a, T, F>(mut format_exact: F, v: T, sign: Sign, ndigits: usize, upper: bool, buf: &'a mut [u8], parts: &'a mut [Part<'a>]) -> Formatted<'a> @@ -600,8 +600,8 @@ pub fn to_exact_exp_str<'a, T, F>(mut format_exact: F, v: T, /// The byte buffer should be enough for the output unless `frac_digits` is /// so large that only the fixed number of digits will be ever written. /// (The tipping point for `f64` is about 800, and 1000 bytes should be enough.) -/// There should be at least 5 parts available, due to the worst case like -/// `[+][0.][0000][45][0000]` with `frac_digits = 10`. +/// There should be at least 4 parts available, due to the worst case like +/// `[+][0.][0000][2][0000]` with `frac_digits = 10`. pub fn to_exact_fixed_str<'a, T, F>(mut format_exact: F, v: T, sign: Sign, frac_digits: usize, _upper: bool, buf: &'a mut [u8], parts: &'a mut [Part<'a>]) -> Formatted<'a> From a9cb094879fabd23774a0d9dcfed7f3eeb9a4aff Mon Sep 17 00:00:00 2001 From: Felix Raimundo Date: Sat, 13 May 2017 21:42:51 +0200 Subject: [PATCH 2/5] Explain why `thread::yield_now` could be used. Part of #29378. --- src/libstd/thread/mod.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 200368be275c3..8f1a88ed30515 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -468,6 +468,23 @@ pub fn current() -> Thread { /// Cooperatively gives up a timeslice to the OS scheduler. /// +/// This is used when the programmer knows that the thread will have nothing +/// to do for some time, and thus avoid wasting computing time. +/// +/// For example when polling on a resource, it is common to check that it is +/// available, and if not to yield in order to avoid busy waiting. +/// +/// Thus the pattern of `yield`ing after a failed poll is rather common when +/// implementing low-level shared resources or synchronization primitives. +/// +/// However programmers will usualy prefer to use, [`channel`]s, [`Condvar`]s, +/// [`Mutex`]es or [`join`] for their synchronisation routines, as they avoid +/// thinking about thread schedulling. +/// +/// Note that [`channel`]s for example are implemented using this primitive. +/// Indeed when you call `send` or `recv`, which are blocking, they will yield +/// if the channel is not available. +/// /// # Examples /// /// ``` @@ -475,6 +492,12 @@ pub fn current() -> Thread { /// /// thread::yield_now(); /// ``` +/// +/// [`channel`]: ../../std/sync/mpsc/index.html +/// [`spawn`]: ../../std/thread/fn.spawn.html +/// [`join`]: ../../std/thread/struct.JoinHandle.html#method.join +/// [`Mutex`]: ../../std/sync/struct.Mutex.html +/// [`Condvar`]: ../../std/sync/struct.Condvar.html #[stable(feature = "rust1", since = "1.0.0")] pub fn yield_now() { imp::Thread::yield_now() From 21ca9cab7d3a91379005546ac6b0e8c4118e0f34 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Sun, 14 May 2017 17:56:24 +0100 Subject: [PATCH 3/5] Fix some dead links in The Unstable Book --- .../src/language-features/advanced-slice-patterns.md | 2 +- src/doc/unstable-book/src/language-features/asm.md | 2 +- src/doc/unstable-book/src/language-features/box-patterns.md | 2 +- src/doc/unstable-book/src/language-features/box-syntax.md | 2 +- src/doc/unstable-book/src/language-features/global_asm.md | 4 ++-- .../unstable-book/src/language-features/plugin-registrar.md | 2 +- src/doc/unstable-book/src/language-features/plugin.md | 2 +- src/doc/unstable-book/src/language-features/slice-patterns.md | 3 ++- src/doc/unstable-book/src/library-features/alloc-jemalloc.md | 2 +- src/doc/unstable-book/src/library-features/alloc-system.md | 2 +- 10 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/doc/unstable-book/src/language-features/advanced-slice-patterns.md b/src/doc/unstable-book/src/language-features/advanced-slice-patterns.md index 30d22ca8208bf..e8256469b1450 100644 --- a/src/doc/unstable-book/src/language-features/advanced-slice-patterns.md +++ b/src/doc/unstable-book/src/language-features/advanced-slice-patterns.md @@ -4,7 +4,7 @@ The tracking issue for this feature is: [#23121] [#23121]: https://github.com/rust-lang/rust/issues/23121 -See also [`slice_patterns`](slice-patterns.html). +See also [`slice_patterns`](language-features/slice-patterns.html). ------------------------ diff --git a/src/doc/unstable-book/src/language-features/asm.md b/src/doc/unstable-book/src/language-features/asm.md index 5e68be633e7ab..8deb8f4625620 100644 --- a/src/doc/unstable-book/src/language-features/asm.md +++ b/src/doc/unstable-book/src/language-features/asm.md @@ -190,4 +190,4 @@ constraints, etc. [llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions If you need more power and don't mind losing some of the niceties of -`asm!`, check out [global_asm](global_asm.html). +`asm!`, check out [global_asm](language-features/global_asm.html). diff --git a/src/doc/unstable-book/src/language-features/box-patterns.md b/src/doc/unstable-book/src/language-features/box-patterns.md index 86346364a7135..0896627acae1b 100644 --- a/src/doc/unstable-book/src/language-features/box-patterns.md +++ b/src/doc/unstable-book/src/language-features/box-patterns.md @@ -4,7 +4,7 @@ The tracking issue for this feature is: [#29641] [#29641]: https://github.com/rust-lang/rust/issues/29641 -See also [`box_syntax`](box-syntax.html) +See also [`box_syntax`](language-features/box-syntax.html) ------------------------ diff --git a/src/doc/unstable-book/src/language-features/box-syntax.md b/src/doc/unstable-book/src/language-features/box-syntax.md index 47aade0d04563..50e59231a4df2 100644 --- a/src/doc/unstable-book/src/language-features/box-syntax.md +++ b/src/doc/unstable-book/src/language-features/box-syntax.md @@ -4,7 +4,7 @@ The tracking issue for this feature is: [#27779] [#27779]: https://github.com/rust-lang/rust/issues/27779 -See also [`box_patterns`](box-patterns.html) +See also [`box_patterns`](language-features/box-patterns.html) ------------------------ diff --git a/src/doc/unstable-book/src/language-features/global_asm.md b/src/doc/unstable-book/src/language-features/global_asm.md index 44921aa309f84..f1ef74a63b513 100644 --- a/src/doc/unstable-book/src/language-features/global_asm.md +++ b/src/doc/unstable-book/src/language-features/global_asm.md @@ -74,5 +74,5 @@ usages and placed the larger, single usage in the crate root. If you don't need quite as much power and flexibility as `global_asm!` provides, and you don't mind restricting your inline -assembly to `fn` bodies only, you might try the [asm](asm.html) -feature instead. +assembly to `fn` bodies only, you might try the +[asm](language-features/asm.html) feature instead. diff --git a/src/doc/unstable-book/src/language-features/plugin-registrar.md b/src/doc/unstable-book/src/language-features/plugin-registrar.md index ca3738bd93f83..b16e2ac2d221c 100644 --- a/src/doc/unstable-book/src/language-features/plugin-registrar.md +++ b/src/doc/unstable-book/src/language-features/plugin-registrar.md @@ -8,6 +8,6 @@ This feature is part of "compiler plugins." It will often be used with the [`plugin`] and `rustc_private` features as well. For more details, see their docs. -[`plugin`]: plugin.html +[`plugin`]: language-features/plugin.html ------------------------ diff --git a/src/doc/unstable-book/src/language-features/plugin.md b/src/doc/unstable-book/src/language-features/plugin.md index 3a1872e18ddb8..4b8603e3c4450 100644 --- a/src/doc/unstable-book/src/language-features/plugin.md +++ b/src/doc/unstable-book/src/language-features/plugin.md @@ -8,7 +8,7 @@ The tracking issue for this feature is: [#29597] This feature is part of "compiler plugins." It will often be used with the [`plugin_registrar`] and `rustc_private` features. -[`plugin_registrar`]: plugin-registrar.html +[`plugin_registrar`]: language-features/plugin-registrar.html ------------------------ diff --git a/src/doc/unstable-book/src/language-features/slice-patterns.md b/src/doc/unstable-book/src/language-features/slice-patterns.md index 1e9e1eaafda46..69857297582da 100644 --- a/src/doc/unstable-book/src/language-features/slice-patterns.md +++ b/src/doc/unstable-book/src/language-features/slice-patterns.md @@ -4,7 +4,8 @@ The tracking issue for this feature is: [#23121] [#23121]: https://github.com/rust-lang/rust/issues/23121 -See also [`advanced_slice_patterns`](advanced-slice-patterns.html). +See also +[`advanced_slice_patterns`](language-features/advanced-slice-patterns.html). ------------------------ diff --git a/src/doc/unstable-book/src/library-features/alloc-jemalloc.md b/src/doc/unstable-book/src/library-features/alloc-jemalloc.md index 9bffa2ff99bf3..18ff838dd32b9 100644 --- a/src/doc/unstable-book/src/library-features/alloc-jemalloc.md +++ b/src/doc/unstable-book/src/library-features/alloc-jemalloc.md @@ -4,7 +4,7 @@ The tracking issue for this feature is: [#33082] [#33082]: https://github.com/rust-lang/rust/issues/33082 -See also [`alloc_system`](alloc-system.html). +See also [`alloc_system`](library-features/alloc-system.html). ------------------------ diff --git a/src/doc/unstable-book/src/library-features/alloc-system.md b/src/doc/unstable-book/src/library-features/alloc-system.md index 6fa89179d8e11..1d261db6ba1b3 100644 --- a/src/doc/unstable-book/src/library-features/alloc-system.md +++ b/src/doc/unstable-book/src/library-features/alloc-system.md @@ -4,7 +4,7 @@ The tracking issue for this feature is: [#33082] [#33082]: https://github.com/rust-lang/rust/issues/33082 -See also [`alloc_jemalloc`](alloc-jemalloc.html). +See also [`alloc_jemalloc`](library-features/alloc-jemalloc.html). ------------------------ From d4f20eb7e32bad9049663d30cfcb0e246ef2e031 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Sun, 14 May 2017 17:57:59 +0100 Subject: [PATCH 4/5] linkchecker: Add support for tag Add support for the HTML tag as used by mdBook so The Unstable Book can be checked. Also cleanup a few things: * Stop checking the name attribute. It should never have been used and mdBook has since been fixed not to use it. * Make sure we only check html files. * Remove a few unnecessary allocations. Finally, dead links in The Unstable Book have been fixed. --- src/tools/linkchecker/main.rs | 89 +++++++++++++---------------------- 1 file changed, 33 insertions(+), 56 deletions(-) diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 3d9a4fba6cdee..1b55dc792c2e5 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -41,7 +41,7 @@ macro_rules! t { } fn main() { - let docs = env::args().nth(1).unwrap(); + let docs = env::args_os().nth(1).unwrap(); let docs = env::current_dir().unwrap().join(docs); let mut errors = false; walk(&mut HashMap::new(), &docs, &docs, &mut errors); @@ -65,7 +65,6 @@ enum Redirect { struct FileEntry { source: String, ids: HashSet, - names: HashSet, } type Cache = HashMap; @@ -73,7 +72,7 @@ type Cache = HashMap; impl FileEntry { fn parse_ids(&mut self, file: &Path, contents: &str, errors: &mut bool) { if self.ids.is_empty() { - with_attrs_in_source(contents, " id", |fragment, i| { + with_attrs_in_source(contents, " id", |fragment, i, _| { let frag = fragment.trim_left_matches("#").to_owned(); if !self.ids.insert(frag) { *errors = true; @@ -82,15 +81,6 @@ impl FileEntry { }); } } - - fn parse_names(&mut self, contents: &str) { - if self.names.is_empty() { - with_attrs_in_source(contents, " name", |fragment, _| { - let frag = fragment.trim_left_matches("#").to_owned(); - self.names.insert(frag); - }); - } - } } fn walk(cache: &mut Cache, root: &Path, dir: &Path, errors: &mut bool) { @@ -116,15 +106,8 @@ fn check(cache: &mut Cache, file: &Path, errors: &mut bool) -> Option { - // ignore js files as they are not prone to errors as the rest of the - // documentation is and they otherwise bring up false positives. - if file.extension().and_then(|s| s.to_str()) == Some("js") { - return None; - } - - // ignore handlebars files as they use {{}} to build links, we only - // want to test the generated files - if file.extension().and_then(|s| s.to_str()) == Some("hbs") { + // Ignore none HTML files. + if file.extension().and_then(|s| s.to_str()) != Some("html") { return None; } @@ -147,13 +130,7 @@ fn check(cache: &mut Cache, return None; } - // mdbook uses the HTML tag to handle links for subdirectories, which - // linkchecker doesn't support - if file.to_str().unwrap().contains("unstable-book") { - return None; - } - - let res = load_file(cache, root, PathBuf::from(file), SkipRedirect); + let res = load_file(cache, root, file, SkipRedirect); let (pretty_file, contents) = match res { Ok(res) => res, Err(_) => return None, @@ -162,13 +139,10 @@ fn check(cache: &mut Cache, cache.get_mut(&pretty_file) .unwrap() .parse_ids(&pretty_file, &contents, errors); - cache.get_mut(&pretty_file) - .unwrap() - .parse_names(&contents); } // Search for anything that's the regex 'href[ ]*=[ ]*".*?"' - with_attrs_in_source(&contents, " href", |url, i| { + with_attrs_in_source(&contents, " href", |url, i, base| { // Ignore external URLs if url.starts_with("http:") || url.starts_with("https:") || url.starts_with("javascript:") || url.starts_with("ftp:") || @@ -184,9 +158,9 @@ fn check(cache: &mut Cache, // Once we've plucked out the URL, parse it using our base url and // then try to extract a file path. let mut path = file.to_path_buf(); - if !url.is_empty() { + if !base.is_empty() || !url.is_empty() { path.pop(); - for part in Path::new(url).components() { + for part in Path::new(base).join(url).components() { match part { Component::Prefix(_) | Component::RootDir => panic!(), @@ -197,13 +171,6 @@ fn check(cache: &mut Cache, } } - if let Some(extension) = path.extension() { - // don't check these files - if extension == "png" { - return; - } - } - // Alright, if we've found a file name then this file had better // exist! If it doesn't then we register and print an error. if path.exists() { @@ -218,11 +185,17 @@ fn check(cache: &mut Cache, pretty_path.display()); return; } - let res = load_file(cache, root, path.clone(), FromRedirect(false)); + if let Some(extension) = path.extension() { + // Ignore none HTML files. + if extension != "html" { + return; + } + } + let res = load_file(cache, root, &path, FromRedirect(false)); let (pretty_path, contents) = match res { Ok(res) => res, Err(LoadError::IOError(err)) => { - panic!(format!("error loading {}: {}", path.display(), err)); + panic!("error loading {}: {}", path.display(), err); } Err(LoadError::BrokenRedirect(target, _)) => { *errors = true; @@ -245,11 +218,10 @@ fn check(cache: &mut Cache, let entry = &mut cache.get_mut(&pretty_path).unwrap(); entry.parse_ids(&pretty_path, &contents, errors); - entry.parse_names(&contents); - if !(entry.ids.contains(*fragment) || entry.names.contains(*fragment)) { + if !entry.ids.contains(*fragment) { *errors = true; - print!("{}:{}: broken link fragment ", + print!("{}:{}: broken link fragment ", pretty_file.display(), i + 1); println!("`#{}` pointing to `{}`", fragment, pretty_path.display()); @@ -267,7 +239,7 @@ fn check(cache: &mut Cache, fn load_file(cache: &mut Cache, root: &Path, - mut file: PathBuf, + file: &Path, redirect: Redirect) -> Result<(PathBuf, String), LoadError> { let mut contents = String::new(); @@ -279,9 +251,9 @@ fn load_file(cache: &mut Cache, None } Entry::Vacant(entry) => { - let mut fp = File::open(file.clone()).map_err(|err| { + let mut fp = File::open(file).map_err(|err| { if let FromRedirect(true) = redirect { - LoadError::BrokenRedirect(file.clone(), err) + LoadError::BrokenRedirect(file.to_path_buf(), err) } else { LoadError::IOError(err) } @@ -297,17 +269,14 @@ fn load_file(cache: &mut Cache, entry.insert(FileEntry { source: contents.clone(), ids: HashSet::new(), - names: HashSet::new(), }); } maybe } }; - file.pop(); - match maybe_redirect.map(|url| file.join(url)) { + match maybe_redirect.map(|url| file.parent().unwrap().join(url)) { Some(redirect_file) => { - let path = PathBuf::from(redirect_file); - load_file(cache, root, path, FromRedirect(true)) + load_file(cache, root, &redirect_file, FromRedirect(true)) } None => Ok((pretty_file, contents)), } @@ -329,10 +298,14 @@ fn maybe_redirect(source: &str) -> Option { }) } -fn with_attrs_in_source(contents: &str, attr: &str, mut f: F) { +fn with_attrs_in_source(contents: &str, attr: &str, mut f: F) { + let mut base = ""; for (i, mut line) in contents.lines().enumerate() { while let Some(j) = line.find(attr) { let rest = &line[j + attr.len()..]; + // The base tag should always be the first link in the document so + // we can get away with using one pass. + let is_base = line[..j].ends_with(" Builder { Builder { @@ -280,9 +305,10 @@ impl Builder { self } - /// Spawns a new thread, and returns a join handle for it. + /// Spawns a new thread by taking ownership of the `Builder`, and returns an + /// [`io::Result`] to its [`JoinHandle`]. /// - /// The child thread may outlive the parent (unless the parent thread + /// The spawned thread may outlive the caller (unless the caller thread /// is the main thread; the whole process is terminated when the main /// thread finishes). The join handle can be used to block on /// termination of the child thread, including recovering its panics. @@ -297,6 +323,7 @@ impl Builder { /// /// [`spawn`]: ../../std/thread/fn.spawn.html /// [`io::Result`]: ../../std/io/type.Result.html + /// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html /// /// # Examples ///