blonk
1
Given this:
pub fn mktbldoc<H, B, F>(hbldr: Option<H>, bbldr: B, fbldr: Option<F>) -> Doc
where
H: Fn(&mut sidoc::Builder),
B: Fn(&mut sidoc::Builder),
F: Fn(&mut sidoc::Builder)
{
// ...
}
.. let's say I want to call mktbldoc()
, but I don't want to construct a header or footer:
mktbldoc(None, |foo| {}, None);
The compiler will fail because:
cannot infer type for type parameter `H` declared on the function `mktbldoc`
Any nice ways to solve this on a type level (which isn't overly verbose)? (The solutions I come up cause more runtime penalties).
Heh, basically the same as @2e71828's suggestion in a different thread just now, you could pass in a no-op function.
fn nop(&mut sidoc::Builder) {}
pub fn mktbldoc<H, B, F>(hbldr: H, bbldr: B, fbldr: F) -> Doc
where
H: Fn(&mut sidoc::Builder),
B: Fn(&mut sidoc::Builder),
F: Fn(&mut sidoc::Builder)
{
todo!()
}
// ...
mktbldoc(nop, |foo| {}, nop);
Although I think in this case, you might not need the nop function.
mktbldoc(|_|{}, |foo| {}, |_|{});
1 Like
blonk
3
The issue I have is this:
if let Some(hbldr) = hbldr {
bldr.scope("<thead>", Some("</thead>"));
hbldr(&mut bldr);
bldr.exit();
}
So basically the Some()
/None
is used to control whether something is added or not in addition to what the callback would add.
Experimenting with this instead:
type DocBldFn = fn(&mut sidoc::Builder);
pub fn mktbldoc2(
hbldr: Option<DocBldFn>,
bbldr: DocBldFn,
fbldr: Option<DocBldFn>
) {
}
If you need a typed None
around, you can declare a const
one:
pub fn mktbldoc<H, B, F>(hbldr: Option<H>, bbldr: B, fbldr: Option<F>) -> Doc
where
H: Fn(&mut sidoc::Builder),
B: Fn(&mut sidoc::Builder),
F: Fn(&mut sidoc::Builder)
{
todo!()
}
// the new part
const NOP: Option<fn (&mut sidoc::Builder)> = None;
// ...
mktbldoc(NOP, |foo| {}, NOP);
1 Like
Imo even better than @quinedot’s solution is getting a zero-sized option type (by using an uninhabited function type). You can do something like this:
#[inline]
pub fn nop() -> Option<impl Fn(&mut sidoc::Builder)> {
enum Void {}
None::<Void>.map(|void| move |_: &mut sidoc::Builder| match void {})
}
println!("{}", std::mem::size_of_val(&NOP)); // -> 8
println!("{}", std::mem::size_of_val(&nop())); // -> 0
(playground)
Edit 2022: This code will need slight modification to get the same zero-sized option behavior in edition 2021.
5 Likes
system
Closed
7
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.