dtolnay / case-studies Goto Github PK
View Code? Open in Web Editor NEWAnalysis of various tricky Rust code
License: Apache License 2.0
Analysis of various tricky Rust code
License: Apache License 2.0
// Before
fn f(&self, a: Arg1, b: Arg2) -> Ret {
/* original function body */
}
// After
fn f(&self, a: Arg1, b: Arg2) -> Ret {
struct Guard; //Need to complicate this type name until Macro 2.0
//The function body might use the same name
impl Drop for Guard {
fn drop(&mut self) {
/* do the thing */
}
}
let guard = Guard; //No need to change variable name
//Even when the function body uses the same name
let original_f = move || -> Ret {
/*
* original function body
* Let the compiler capture self, args etc
*/
};
let value = original_f();
mem::forget(guard);
value
}
The future section in Multiple of 8 const assertion
talks about creating a const_assert rfc.
The already accepted rfc for assertions in constants is this one,
which combined with const_wildcard would allow doing const assertions outside of any item.
Example of how it will look once both RFCS are fully implemented:
const _:()=assert!(SIZE % 8 == 0, "total size is required to be a multiple of 8 bits");
unit-type-parameters/README.md#documentation
This section should call out that type_alias_bounds is a future compatibility lint in the sense that the compiler may enforce the bounds eventually and the current behavior is considered a compiler bug.
The thing that makes it safe and correct to write here is that the RHS of the type alias uses exactly the same bounds as the LHS. Where that isn't the case, future compiler changes may break it.
Hey David,
Sorry if GitHub Issues isn’t the right forum for this, seemed better than reviving an old Reddit thread. I have gotten Autoref specialization to work well in toy cases, but my actual use case has an associated type in it and that causes things to fall down. As a simple (nonsensical) example:
trait MyTrait {
type MyAssociatedType;
}
impl<T: Clone> MyTrait for &T {
type MyAssociatedType = bool;
}
impl MyTrait for String {
type MyAssociatedType = str;
}
fn<T: MyTrait> get_toy_example(input: T): <T as MyTrait>::MyAssociatedType {
...
}
As far as I can tell the issue is simply that Autoref does not apply to the <T as MyTrait>
section, so it will not find implementations for anything other than String. If I change it to <&T as MyTrait>
then it will find implementations for all Clone
structs but will not special-case String.
The experimental specialization feature built into Rust also falls down for associated types (and seems to be gathering dust) so I’m sort of stuck here. You seem to be the foremost expert on Rust specialization so I figured I’d ask :) Am I hosed here?
If so, might be worth updating the case study doc with that second caveat added. It does come up pretty high up on the Google results for Rust specialization.
Not sure if issues is an appropriate place for such discussion, but after looking at #11 thought I'd share an alternative approach I've been using.
Autoref specialization case study mentions that it works only in macros but not in generic contexts like
pub fn demo<T: ???>(value: T) -> String {
(&value).my_to_string()
}
However, one trick I've found to work well in such contexts is comparing TypeId
s, e.g.:
pub fn format<T: 'static + ?Sized + std::fmt::Debug>(value: &T) -> String {
use std::any::TypeId;
if TypeId::of::<T>() == TypeId::of::<[u8]>() {
format!("{:X?}", value)
} else {
format!("{:?}", value)
}
}
It has own limitations, namely it works only for 'static
types due to restrictions on TypeId
, but it's sometimes enough and works at least in some generic contexts.
Moreover, since the condition is comparing two constant values, optimiser is always able to remove it altogether in each monomorphised version of the function and instead unconditionally execute the correct branch, so this approach ends up being zero-cost, just like native specialization.
The problem with a macro definition such as:
macro_rules! anyhow {
($err:expr) => ({
#[allow(unused_imports)]
use $crate::{DisplayKind, StdErrorKind};
let error = $err;
(&error).anyhow_kind().new(error)
});
}
Is that it won't work if $err
relies on temporaries (e.g. it is format_args!
). However, the following will work:
macro_rules! anyhow {
($err:expr) => ({
#[allow(unused_imports)]
use $crate::{DisplayKind, StdErrorKind};
match $err {
error => (&error).anyhow_kind().new(error),
}
});
}
as it's just one expression.
I haven't fully thought this through, but I think you could emulate a class hierarchy using repr[transparent]
and mem::transmute
on references. This hasn't been done I assume because there is no reason a sane person would do this 😋
I'm in the process of moving overflower to autoref specialization. I have found that it works as you described in the unary operation case (e.g. specializing std::ops::Neg
vs. overflower::OverflowerNeg
).
However, there is a small niggle when the trait is generic over some other type as for example std::ops::Add<RHS = Self>
is over RHS
. In this case, if I try to implement the kind for T: std::ops::Add
, this only works for the default RHS type (which is Self
, but e.g. String
implements Add
for various other types (e.g. &'_ str
and Cow<'_, str>
).
Thus we must allow our kind to be implemented for arbitrary RHS
. So let's try that:
pub struct OverflowerAddTag;
pub trait OverflowerAddKind<R> {
fn overflower_add_tag() -> OverflowerAddTag {
OverflowerAddTag
}
}
impl<R, T> OverflowerAddKind<R> for T where &T: std::ops::Add<R> {}
impl<R, T> OverflowerAddKind<R> for T where T: OverflowerAdd<R> {}
Now the compiler tells us that we need to give a lifetime to &T
, so we do that, which gives us:
impl<'a, R, T: 'a> OverflowerAddKind<R> for T where &'a T: std::ops::Add<R> {}
This works. Just wanted to let you know.
Thanks for writing up the autoref specialization guide!
There's a similar technique which depends on Rust favoring inherent impls over traits.
Taking the DisplayToString
example:
use std::fmt::{Display, Write};
pub trait DisplayToString {
fn my_to_string(&self) -> String;
}
pub struct DisplayToStringWrapper<'a, T: ?Sized>(pub &'a T);
// This is an inherent method, so it's tried first
impl<'a, T: AsRef<str> + ?Sized> DisplayToStringWrapper<'a, T> {
pub fn my_to_string(&self) -> String {
println!("called specialized impl");
self.0.as_ref().into()
}
}
// This is only used if the inherent method fails to type-check
impl<'a, T: Display + ?Sized> DisplayToString for DisplayToStringWrapper<'a, T> {
fn my_to_string(&self) -> String {
println!("blanket impl");
self.to_string()
}
}
This can be more reliable than the autoref approach. For example, (&&String::from("hello")).my_to_string()
will fall back to the slow path using autoref specialization but stick to the fast path with inherent impls. The drawback is that it only allows for one fallback case. Overall, I think this approach makes some interesting tradeoffs and may be worth calling (hehe) out in the article!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.