Skip to content

Commit 4b3257a

Browse files
refactor: port anymap
1 parent 0427a23 commit 4b3257a

File tree

7 files changed

+468
-9
lines changed

7 files changed

+468
-9
lines changed

Cargo.lock

Lines changed: 25 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ debug = 0
4646

4747
[workspace.dependencies]
4848
# local crates
49+
anymap = { path = "./crates/anymap", version = "0.0.0" }
4950
base-db = { path = "./crates/base-db", version = "0.0.0" }
5051
cfg = { path = "./crates/cfg", version = "0.0.0" }
5152
flycheck = { path = "./crates/flycheck", version = "0.0.0" }
@@ -91,9 +92,9 @@ lsp-server = { version = "0.7.4" }
9192

9293
# non-local crates
9394
smallvec = { version = "1.10.0", features = [
94-
"const_new",
95-
"union",
96-
"const_generics",
95+
"const_new",
96+
"union",
97+
"const_generics",
9798
] }
9899
smol_str = "0.2.0"
99100
nohash-hasher = "0.2.0"
@@ -103,5 +104,12 @@ serde_json = "1.0.96"
103104
triomphe = { version = "0.1.8", default-features = false, features = ["std"] }
104105
# can't upgrade due to dashmap depending on 0.12.3 currently
105106
hashbrown = { version = "0.12.3", features = [
106-
"inline-more",
107+
"inline-more",
107108
], default-features = false }
109+
110+
rustc_lexer = { version = "0.10.0", package = "ra-ap-rustc_lexer" }
111+
rustc_parse_format = { version = "0.10.0", package = "ra-ap-rustc_parse_format", default-features = false }
112+
113+
# Upstream broke this for us so we can't update it
114+
rustc_abi = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_abi", default-features = false }
115+
rustc_index = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_index", default-features = false }

crates/anymap/Cargo.toml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[package]
2+
name = "anymap"
3+
version = "0.0.0"
4+
description = "This crate is a port of only the necessary features from https://github.com/chris-morgan/anymap for use within rust-analyzer. Copyright © 2014–2022 Chris Morgan. COPYING: https://github.com/chris-morgan/anymap/blob/master/COPYING"
5+
6+
authors.workspace = true
7+
edition.workspace = true
8+
license.workspace = true
9+
rust-version.workspace = true
10+
11+
[package.metadata.docs.rs]
12+
all-features = true
13+
14+
[features]
15+
default = ["std"]
16+
std = []
17+
18+
[dependencies]
19+
# The hashbrown feature, disabled by default, is exposed under different stability guarantees than the usual SemVer ones: by preference the version range will only be extended, but it may be shrunk in a MINOR release. See README.md.
20+
hashbrown = { version = "0.14.0", optional = true }

crates/anymap/src/any.rs

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
//! Copyright © 2014–2022 Chris Morgan
2+
//! https://github.com/chris-morgan/anymap/blob/master/COPYING
3+
//! impl some traits for dyn Any
4+
use core::any::{Any, TypeId};
5+
use core::fmt;
6+
7+
#[doc(hidden)]
8+
pub trait CloneToAny {
9+
/// Clone `self` into a new `Box<dyn CloneAny>` object.
10+
fn clone_to_any(&self) -> Box<dyn CloneAny>;
11+
}
12+
13+
impl<T: Any + Clone> CloneToAny for T {
14+
#[inline]
15+
fn clone_to_any(&self) -> Box<dyn CloneAny> {
16+
Box::new(self.clone())
17+
}
18+
}
19+
20+
macro_rules! impl_clone {
21+
($t:ty) => {
22+
impl Clone for Box<$t> {
23+
#[inline]
24+
fn clone(&self) -> Box<$t> {
25+
// SAFETY: this dance is to reapply any Send/Sync marker. I’m not happy about this
26+
// approach, given that I used to do it in safe code, but then came a dodgy
27+
// future-compatibility warning where_clauses_object_safety, which is spurious for
28+
// auto traits but still super annoying (future-compatibility lints seem to mean
29+
// your bin crate needs a corresponding allow!). Although I explained my plight¹
30+
// and it was all explained and agreed upon, no action has been taken. So I finally
31+
// caved and worked around it by doing it this way, which matches what’s done for
32+
// core::any², so it’s probably not *too* bad.
33+
//
34+
// ¹ https://github.com/rust-lang/rust/issues/51443#issuecomment-421988013
35+
// ² https://github.com/rust-lang/rust/blob/e7825f2b690c9a0d21b6f6d84c404bb53b151b38/library/alloc/src/boxed.rs#L1613-L1616
36+
let clone: Box<dyn CloneAny> = (**self).clone_to_any();
37+
let raw: *mut dyn CloneAny = Box::into_raw(clone);
38+
unsafe { Box::from_raw(raw as *mut $t) }
39+
}
40+
}
41+
42+
impl fmt::Debug for $t {
43+
#[inline]
44+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45+
f.pad(stringify!($t))
46+
}
47+
}
48+
};
49+
}
50+
51+
/// Methods for downcasting from an `Any`-like trait object.
52+
///
53+
/// This should only be implemented on trait objects for subtraits of `Any`, though you can
54+
/// implement it for other types and it’ll work fine, so long as your implementation is correct.
55+
pub trait Downcast {
56+
/// Gets the `TypeId` of `self`.
57+
fn type_id(&self) -> TypeId;
58+
59+
// Note the bound through these downcast methods is 'static, rather than the inexpressible
60+
// concept of Self-but-as-a-trait (where Self is `dyn Trait`). This is sufficient, exceeding
61+
// TypeId’s requirements. Sure, you *can* do CloneAny.downcast_unchecked::<NotClone>() and the
62+
// type system won’t protect you, but that doesn’t introduce any unsafety: the method is
63+
// already unsafe because you can specify the wrong type, and if this were exposing safe
64+
// downcasting, CloneAny.downcast::<NotClone>() would just return an error, which is just as
65+
// correct.
66+
//
67+
// Now in theory we could also add T: ?Sized, but that doesn’t play nicely with the common
68+
// implementation, so I’m doing without it.
69+
70+
/// Downcast from `&Any` to `&T`, without checking the type matches.
71+
///
72+
/// # Safety
73+
///
74+
/// The caller must ensure that `T` matches the trait object, on pain of *undefined behaviour*.
75+
unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T;
76+
77+
/// Downcast from `&mut Any` to `&mut T`, without checking the type matches.
78+
///
79+
/// # Safety
80+
///
81+
/// The caller must ensure that `T` matches the trait object, on pain of *undefined behaviour*.
82+
unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T;
83+
}
84+
85+
/// A trait for the conversion of an object into a boxed trait object.
86+
pub trait IntoBox<A: ?Sized + Downcast>: Any {
87+
/// Convert self into the appropriate boxed form.
88+
fn into_box(self) -> Box<A>;
89+
}
90+
91+
macro_rules! implement {
92+
($any_trait:ident $(+ $auto_traits:ident)*) => {
93+
impl Downcast for dyn $any_trait $(+ $auto_traits)* {
94+
#[inline]
95+
fn type_id(&self) -> TypeId {
96+
self.type_id()
97+
}
98+
99+
#[inline]
100+
unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
101+
&*(self as *const Self as *const T)
102+
}
103+
104+
#[inline]
105+
unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
106+
&mut *(self as *mut Self as *mut T)
107+
}
108+
}
109+
110+
impl<T: $any_trait $(+ $auto_traits)*> IntoBox<dyn $any_trait $(+ $auto_traits)*> for T {
111+
#[inline]
112+
fn into_box(self) -> Box<dyn $any_trait $(+ $auto_traits)*> {
113+
Box::new(self)
114+
}
115+
}
116+
}
117+
}
118+
119+
implement!(Any);
120+
implement!(Any + Send);
121+
implement!(Any + Send + Sync);
122+
123+
/// [`Any`], but with cloning.
124+
///
125+
/// Every type with no non-`'static` references that implements `Clone` implements `CloneAny`.
126+
/// See [`core::any`] for more details on `Any` in general.
127+
pub trait CloneAny: Any + CloneToAny {}
128+
impl<T: Any + Clone> CloneAny for T {}
129+
implement!(CloneAny);
130+
implement!(CloneAny + Send);
131+
implement!(CloneAny + Send + Sync);
132+
impl_clone!(dyn CloneAny);
133+
impl_clone!(dyn CloneAny + Send);
134+
impl_clone!(dyn CloneAny + Send + Sync);

0 commit comments

Comments
 (0)