-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathfmt.rs
91 lines (79 loc) · 2.69 KB
/
fmt.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use std::collections::HashMap;
use syn::{Ident, Path};
const FMT_TRAITS: &[(&str, &str)] = &[
("Display", ""),
("Debug", "?"),
("Octal", "o"),
("LowerHex", "x"),
("UpperHex", "X"),
("Pointer", "p"),
("Binary", "b"),
("LowerExp", "e"),
("UpperExp", "E"),
];
// fmt is a tricky beast, we need to employ custom wrapping to make it work across FFI-boundary.
fn get_custom_impl(fmt_str: &str, crate_path: &TokenStream) -> TokenStream {
quote! {
#[custom_impl(
// Types within the C interface other than self and additional wrappers.
{
f_out: &mut WriteMut,
},
// Unwrapped return type
Result<(), ::core::fmt::Error>,
// Conversion in trait impl to C arguments (signature names are expected).
{
let f_out: WriteBaseMut<::core::fmt::Formatter> = From::from(f);
let f_out = &mut #crate_path::trait_group::Opaquable::into_opaque(f_out);
},
// This is the body of C impl minus the automatic wrapping.
{
write!(f_out, #fmt_str, this)
},
// This part is processed in the trait impl after the call returns (impl_func_ret,
// nothing extra needs to happen here).
{
},
)]
}
}
pub fn fmt_impls() -> TokenStream {
let mut out = TokenStream::new();
let crate_path = crate::util::crate_path();
for (name, ty) in FMT_TRAITS {
let wrap_impl = get_custom_impl(&format!("{{:{}}}", ty), &crate_path);
let ident = format_ident!("{}", name);
out.extend(quote! {
pub trait #ident {
#[int_result]
#wrap_impl
fn fmt(
&self,
f: &mut ::core::fmt::Formatter
) -> Result<(), ::core::fmt::Error>;
}
});
}
out
}
pub fn get_impl(parent_path: &Path, out: &mut Vec<(Path, TokenStream)>) {
let cur_path = super::super::join_paths(parent_path, format_ident!("fmt"));
let fmt_impls = fmt_impls();
out.push((
cur_path,
quote! {
pub trait Write {
#[int_result]
fn write_str(&mut self, s: &str) -> Result<(), ::core::fmt::Error>;
}
#fmt_impls
},
));
}
pub fn get_exports(parent_path: &Path, exports: &mut HashMap<Ident, Path>) {
let cur_path = super::super::join_paths(parent_path, format_ident!("fmt"));
exports.insert(format_ident!("Debug"), cur_path.clone());
exports.insert(format_ident!("Display"), cur_path);
}