Transition a few fmt::Display impls to functions
This introduces a WithFormatter abstraction that permits one-time fmt::Display on an arbitrary closure, created via `display_fn`. This allows us to prevent allocation while still using functions instead of structs, which are a bit unwieldy to thread arguments through as they can't easily call each other (and are generally a bit opaque). The eventual goal here is likely to move us off of the formatting infrastructure entirely in favor of something more structured, but this is a good step to move us in that direction as it makes, for example, passing a context describing current state to the formatting impl much easier.
This commit is contained in:
parent
dafdfee33e
commit
edfd5556f1
2 changed files with 56 additions and 52 deletions
|
@ -6,6 +6,7 @@
|
||||||
//! them in the future to instead emit any format desired.
|
//! them in the future to instead emit any format desired.
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::cell::Cell;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
|
@ -38,8 +39,6 @@ pub struct AsyncSpace(pub hir::IsAsync);
|
||||||
pub struct MutableSpace(pub clean::Mutability);
|
pub struct MutableSpace(pub clean::Mutability);
|
||||||
/// Wrapper struct for emitting type parameter bounds.
|
/// Wrapper struct for emitting type parameter bounds.
|
||||||
pub struct GenericBounds<'a>(pub &'a [clean::GenericBound]);
|
pub struct GenericBounds<'a>(pub &'a [clean::GenericBound]);
|
||||||
/// Wrapper struct for emitting a comma-separated list of items
|
|
||||||
pub struct CommaSep<'a, T>(pub &'a [T]);
|
|
||||||
pub struct AbiSpace(pub Abi);
|
pub struct AbiSpace(pub Abi);
|
||||||
pub struct DefaultSpace(pub bool);
|
pub struct DefaultSpace(pub bool);
|
||||||
|
|
||||||
|
@ -68,11 +67,6 @@ pub struct WhereClause<'a>{
|
||||||
pub end_newline: bool,
|
pub end_newline: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct HRef<'a> {
|
|
||||||
did: DefId,
|
|
||||||
text: &'a str,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> VisSpace<'a> {
|
impl<'a> VisSpace<'a> {
|
||||||
pub fn get(self) -> &'a Option<clean::Visibility> {
|
pub fn get(self) -> &'a Option<clean::Visibility> {
|
||||||
let VisSpace(v) = self; v
|
let VisSpace(v) = self; v
|
||||||
|
@ -91,14 +85,14 @@ impl ConstnessSpace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: fmt::Display> fmt::Display for CommaSep<'a, T> {
|
fn comma_sep<T: fmt::Display>(items: &[T]) -> impl fmt::Display + '_ {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
display_fn(move |f| {
|
||||||
for (i, item) in self.0.iter().enumerate() {
|
for (i, item) in items.iter().enumerate() {
|
||||||
if i != 0 { write!(f, ", ")?; }
|
if i != 0 { write!(f, ", ")?; }
|
||||||
fmt::Display::fmt(item, f)?;
|
fmt::Display::fmt(item, f)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fmt::Display for GenericBounds<'a> {
|
impl<'a> fmt::Display for GenericBounds<'a> {
|
||||||
|
@ -165,9 +159,9 @@ impl fmt::Display for clean::Generics {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if f.alternate() {
|
if f.alternate() {
|
||||||
write!(f, "<{:#}>", CommaSep(&real_params))
|
write!(f, "<{:#}>", comma_sep(&real_params))
|
||||||
} else {
|
} else {
|
||||||
write!(f, "<{}>", CommaSep(&real_params))
|
write!(f, "<{}>", comma_sep(&real_params))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,9 +259,9 @@ impl fmt::Display for clean::PolyTrait {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
if !self.generic_params.is_empty() {
|
if !self.generic_params.is_empty() {
|
||||||
if f.alternate() {
|
if f.alternate() {
|
||||||
write!(f, "for<{:#}> ", CommaSep(&self.generic_params))?;
|
write!(f, "for<{:#}> ", comma_sep(&self.generic_params))?;
|
||||||
} else {
|
} else {
|
||||||
write!(f, "for<{}> ", CommaSep(&self.generic_params))?;
|
write!(f, "for<{}> ", comma_sep(&self.generic_params))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if f.alternate() {
|
if f.alternate() {
|
||||||
|
@ -452,16 +446,15 @@ fn resolved_path(w: &mut fmt::Formatter<'_>, did: DefId, path: &clean::Path,
|
||||||
write!(w, "{}{:#}", &last.name, last.args)?;
|
write!(w, "{}{:#}", &last.name, last.args)?;
|
||||||
} else {
|
} else {
|
||||||
let path = if use_absolute {
|
let path = if use_absolute {
|
||||||
match href(did) {
|
if let Some((_, _, fqp)) = href(did) {
|
||||||
Some((_, _, fqp)) => {
|
format!("{}::{}",
|
||||||
format!("{}::{}",
|
fqp[..fqp.len() - 1].join("::"),
|
||||||
fqp[..fqp.len() - 1].join("::"),
|
anchor(did, fqp.last().unwrap()))
|
||||||
HRef::new(did, fqp.last().unwrap()))
|
} else {
|
||||||
}
|
last.name.to_string()
|
||||||
None => HRef::new(did, &last.name).to_string(),
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
HRef::new(did, &last.name).to_string()
|
anchor(did, &last.name).to_string()
|
||||||
};
|
};
|
||||||
write!(w, "{}{}", path, last.args)?;
|
write!(w, "{}{}", path, last.args)?;
|
||||||
}
|
}
|
||||||
|
@ -513,35 +506,30 @@ fn primitive_link(f: &mut fmt::Formatter<'_>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper to render type parameters
|
/// Helper to render type parameters
|
||||||
fn tybounds(w: &mut fmt::Formatter<'_>,
|
fn tybounds(param_names: &Option<Vec<clean::GenericBound>>) -> impl fmt::Display + '_ {
|
||||||
param_names: &Option<Vec<clean::GenericBound>>) -> fmt::Result {
|
display_fn(move |f| {
|
||||||
match *param_names {
|
match *param_names {
|
||||||
Some(ref params) => {
|
Some(ref params) => {
|
||||||
for param in params {
|
for param in params {
|
||||||
write!(w, " + ")?;
|
write!(f, " + ")?;
|
||||||
fmt::Display::fmt(param, w)?;
|
fmt::Display::fmt(param, f)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
Ok(())
|
None => Ok(())
|
||||||
}
|
}
|
||||||
None => Ok(())
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> HRef<'a> {
|
pub fn anchor(did: DefId, text: &str) -> impl fmt::Display + '_ {
|
||||||
pub fn new(did: DefId, text: &'a str) -> HRef<'a> {
|
display_fn(move |f| {
|
||||||
HRef { did: did, text: text }
|
if let Some((url, short_ty, fqp)) = href(did) {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> fmt::Display for HRef<'a> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
if let Some((url, short_ty, fqp)) = href(self.did) {
|
|
||||||
write!(f, r#"<a class="{}" href="{}" title="{} {}">{}</a>"#,
|
write!(f, r#"<a class="{}" href="{}" title="{} {}">{}</a>"#,
|
||||||
short_ty, url, short_ty, fqp.join("::"), self.text)
|
short_ty, url, short_ty, fqp.join("::"), text)
|
||||||
} else {
|
} else {
|
||||||
write!(f, "{}", self.text)
|
write!(f, "{}", text)
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> fmt::Result {
|
fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> fmt::Result {
|
||||||
|
@ -555,7 +543,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
|
||||||
}
|
}
|
||||||
// Paths like `T::Output` and `Self::Output` should be rendered with all segments.
|
// Paths like `T::Output` and `Self::Output` should be rendered with all segments.
|
||||||
resolved_path(f, did, path, is_generic, use_absolute)?;
|
resolved_path(f, did, path, is_generic, use_absolute)?;
|
||||||
tybounds(f, param_names)
|
fmt::Display::fmt(&tybounds(param_names), f)
|
||||||
}
|
}
|
||||||
clean::Infer => write!(f, "_"),
|
clean::Infer => write!(f, "_"),
|
||||||
clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()),
|
clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()),
|
||||||
|
@ -564,12 +552,12 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
|
||||||
write!(f, "{}{:#}fn{:#}{:#}",
|
write!(f, "{}{:#}fn{:#}{:#}",
|
||||||
UnsafetySpace(decl.unsafety),
|
UnsafetySpace(decl.unsafety),
|
||||||
AbiSpace(decl.abi),
|
AbiSpace(decl.abi),
|
||||||
CommaSep(&decl.generic_params),
|
comma_sep(&decl.generic_params),
|
||||||
decl.decl)
|
decl.decl)
|
||||||
} else {
|
} else {
|
||||||
write!(f, "{}{}", UnsafetySpace(decl.unsafety), AbiSpace(decl.abi))?;
|
write!(f, "{}{}", UnsafetySpace(decl.unsafety), AbiSpace(decl.abi))?;
|
||||||
primitive_link(f, PrimitiveType::Fn, "fn")?;
|
primitive_link(f, PrimitiveType::Fn, "fn")?;
|
||||||
write!(f, "{}{}", CommaSep(&decl.generic_params), decl.decl)
|
write!(f, "{}{}", comma_sep(&decl.generic_params), decl.decl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clean::Tuple(ref typs) => {
|
clean::Tuple(ref typs) => {
|
||||||
|
@ -583,7 +571,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
|
||||||
}
|
}
|
||||||
many => {
|
many => {
|
||||||
primitive_link(f, PrimitiveType::Tuple, "(")?;
|
primitive_link(f, PrimitiveType::Tuple, "(")?;
|
||||||
fmt::Display::fmt(&CommaSep(many), f)?;
|
fmt::Display::fmt(&comma_sep(many), f)?;
|
||||||
primitive_link(f, PrimitiveType::Tuple, ")")
|
primitive_link(f, PrimitiveType::Tuple, ")")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1063,3 +1051,19 @@ impl fmt::Display for DefaultSpace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crate fn display_fn(
|
||||||
|
f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
|
||||||
|
) -> impl fmt::Display {
|
||||||
|
WithFormatter(Cell::new(Some(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WithFormatter<F>(Cell<Option<F>>);
|
||||||
|
|
||||||
|
impl<F> fmt::Display for WithFormatter<F>
|
||||||
|
where F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
(self.0.take()).unwrap()(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2644,19 +2644,19 @@ fn item_module(w: &mut fmt::Formatter<'_>, cx: &Context,
|
||||||
|
|
||||||
match myitem.inner {
|
match myitem.inner {
|
||||||
clean::ExternCrateItem(ref name, ref src) => {
|
clean::ExternCrateItem(ref name, ref src) => {
|
||||||
use crate::html::format::HRef;
|
use crate::html::format::anchor;
|
||||||
|
|
||||||
match *src {
|
match *src {
|
||||||
Some(ref src) => {
|
Some(ref src) => {
|
||||||
write!(w, "<tr><td><code>{}extern crate {} as {};",
|
write!(w, "<tr><td><code>{}extern crate {} as {};",
|
||||||
VisSpace(&myitem.visibility),
|
VisSpace(&myitem.visibility),
|
||||||
HRef::new(myitem.def_id, src),
|
anchor(myitem.def_id, src),
|
||||||
name)?
|
name)?
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
write!(w, "<tr><td><code>{}extern crate {};",
|
write!(w, "<tr><td><code>{}extern crate {};",
|
||||||
VisSpace(&myitem.visibility),
|
VisSpace(&myitem.visibility),
|
||||||
HRef::new(myitem.def_id, name))?
|
anchor(myitem.def_id, name))?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
write!(w, "</code></td></tr>")?;
|
write!(w, "</code></td></tr>")?;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue