์ ๋ Rust๋ฅผ ์ฒ์ ์ฌ์ฉํ๋ฏ๋ก ์ฌ๊ธฐ์ ๋ถ๋ช ํ ๊ฒ์ ๋์น๊ณ ์์ ๊ฐ๋ฅ์ฑ์ด ์์ง๋ง VS Code ํ์ฅ(๋ค๋ฅธ ๋ชจ๋ ํ์ฅ์ ๋นํ์ฑํํ์ต๋๋ค)์ด ์กด์ฌํ์ง ์๋ ๋ฌธ์ ๋ฅผ ๋ณด๊ณ ํ๋ ์ด์ํ ์๋๋ฆฌ์ค์ ๋ถ๋ช์ณค์ต๋๋ค. .
์๋ณ์๋ก ์ ํ์ ์ฃผ์์ ๋ฌ ์ ์๋ ๋งคํฌ๋ก๋ฅผ ์์ฑํ๊ณ ๊ฐ ์ ํ์ ๋ํ ๋ณํ์ ํฌํจํ๋ ์ด๊ฑฐํ๊ณผ ๋์ผํ์ง๋ง ๋ณํ์ ๋ํ ๊ด๋ จ ๋ฐ์ดํฐ๊ฐ ์๋ '์ ํ ์ด๊ฑฐํ' ์ด๊ฑฐํ์ ์์ฑํ ์ ์์ต๋๋ค. ๋ถ๋ง ์์ด A-OK๋ฅผ ๊ตฌ์ถํฉ๋๋ค. cargo build
๊ฐ ์๋ํฉ๋๋ค.
๊ทธ๋ฌ๋ VS Code์ Rust ํ์ฅ์ 4๊ฐ์ ์ค๋ฅ(E0428)๋ฅผ ๋ณด๊ณ ํฉ๋๋ค.
the name `Message1` is defined multiple times
`Message1` redefined here
note: `Message1` must be defined only once in the type namespace of this enum
the name `Message1` is defined multiple times
previous definition of the type `Message1` here
note: `Message1` must be defined only once in the type namespace of this enum
the name `Message2` is defined multiple times
`Message2` redefined here
note: `Message2` must be defined only once in the type namespace of this enum
the name `Message2` is defined multiple times
previous definition of the type `Message2` here
note: `Message2` must be defined only once in the type namespace of this enum
๋ฌธ์ ์ ์ค์ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
#[message(Test)]
pub struct Message1 {
pub val: i32,
}
#[message(Test)]
pub struct Message2;
#[write_message_type(Test)] // Red squiggly
pub enum Test {
}
cargo expand
์ถ๋ ฅ:
pub struct Message1 {
pub val: i32,
}
pub struct Message2;
pub enum TestTypes {
Message1,
Message2,
}
pub enum Test {
Message1(Message1),
Message2(Message2),
}
ํ์ฅ์ด ์ ํํ๊ณ (๊ทธ๋ฆฌ๊ณ ์์๊ฐ ๋ฉ์์ง๋ฅผ ๋ํ ๋ฐ ์ธ๋ํํ ๋ ์์๋๋ ์ถ๋ ฅ์ ๋น๋ํ๊ณ ์์ฑํ๋ค๋ ์ ์ ๊ฐ์ํ ๋ ๋งคํฌ๋ก ์ฝ๋๊ฐ ๋ง์ ๊ด๋ จ์ฑ์ด ์๋์ง ์ฌ๋ถ๋ ํ์คํ์ง ์์ง๋ง ๋ง์ผ์ ๋๋นํ์ฌ ์ฌ๊ธฐ ์์ต๋๋ค. ๋น ๋ฅด๊ณ , ๋๋ฝ๊ณ , ๋ฏธ์์ฑ์ด๋ฉฐ, ๋งคํฌ๋ก๋ฅผ ์์ฑํ๋ ์ฒซ ๋ฒ์งธ ์๋์ ๋๋ค(์์งํ ์ฌ์ ์ ์ถฉ๋ถํ ์ฝ์ง ์์ ์ํ์์).
lazy_static! {
static ref MESSAGE_MAP: Mutex<HashMap<String, Vec<String>>> = Mutex::new(HashMap::new());
}
#[proc_macro_attribute]
pub fn message(attr: TokenStream, item: TokenStream) -> TokenStream {
match MESSAGE_MAP.lock() {
Ok(mut map) => map.entry(attr.to_string()).or_insert(Vec::new()).push(
syn::parse::<syn::DeriveInput>(item.clone())
.expect("Invalid target for message attr")
.ident
.to_string(),
),
Err(e) => panic!("Message map lock poisoned: '{}'.", e.to_string()),
}
item
}
#[proc_macro_attribute]
pub fn write_message_type(attr: TokenStream, _: TokenStream) -> TokenStream {
let name = attr.to_string();
match MESSAGE_MAP.lock() {
Ok(map) => match map.get(&name) {
Some(entries) => {
let message_type_enumeration_name = syn::parse_str::<syn::Ident>(&(name.clone() + "Types")).expect("Invalid message wrapper name.");
let type_entries: Vec<_>= entries.iter().map(|e| syn::parse_str::<syn::Ident>(e).expect("Something went horribly wrong enumerating the wrapped message types")).collect();
let message_wrapper_name = syn::parse_str::<syn::Variant>(&name).expect("Invalid message wrapper name.");
let wrapper_entries: Vec<_>= entries.iter().map(|e|{
let mut variant = e.clone();
variant += "(";
variant += e;
variant += ")";
syn::parse_str::<syn::Variant>(&variant).expect("Something went horribly wrong enumerating the wrapped message types")}).collect();
(quote! {
pub enum #message_type_enumeration_name {
#(#type_entries),*
}
pub enum #message_wrapper_name {
#(#wrapper_entries),*
}
})
.into()
}
None => panic!("Tried to expand message type wrappers '{}', but no message types were recorded for it!", name)
},
Err(e) => panic!("Message map lock poisoned: '{}'.", e.to_string()),
}
}
VS Code๋ ์ต์ ๋ฒ์ ์ด๊ณ Rust ํ์ฅ ํ๋ก๊ทธ๋จ์ ์ต์ ๋ฒ์ ์ด๋ฉฐ Win 10 ์ค์น๊ฐ ์ต์ ๋ฒ์ ์ ๋๋ค. ๋ด๊ฐ ๊ตฌ์ถํ ์ ์๋ ๊ฒ์ฒ๋ผ, ์ธ์์ ๋์ ์๋์ง๋ง ๋ฌธ์ ํจ๋์ ์ด๋ฌํ ์ค๋ฅ๊ฐ ์๋ ๊ฒ์ด ์ข์ ๊ฒ์ ๋๋ค. ํ์ฅ์ด ์๋ ๋ด ์ฝ๋์ ๋ฌธ์ ๋ผ๋ฉด ์ฌ๊ณผ๋๋ฆฝ๋๋ค.
๋๋์ด ๋ฌธ์ ๋ฅผ ์ฌ๋ฌ ๋ฒ ๊ฒช์๊ณ ์ ์ ๋์ ์ฃผ๋ณ์์์์ต๋๋ค. ๋ด ๊ฒฝํ์ Rust-analyzer์๋ ์ด๋ฐ ๋ฌธ์ ๊ฐ ์๊ณ , ํ๋ฐํ ๊ฐ๋ฐ๋๊ณ ์๋ ์ธ์ด ์๋ฒ์ธ ๊ฒ ๊ฐ๋ค. ์ด ํ์ฅ๊ณผ ํจ๊ป RLS๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์ด ํ์ฅ์ ๋ฐฑ์๋๋ก ๋๋ ์์ฒด VS Code ํ์ฅ์ ์ฌ์ฉํ์ฌ rust-analyzer๋ก ์ ํํด ๋ณด์ญ์์ค. ๋๋ Rust-analyzer๊ฐ ๊ฒฐ๊ตญ RLS 2.0์ด ๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ์ง๋ง ์ด๋ฏธ ์ฌ์ฉํ๊ธฐ ๋ ์ฝ๊ณ ์์งํ ๋งํด์ ๋ ๋์ IDE ๊ฒฝํ์ ์ ๊ณตํฉ๋๋ค.
๋๋ ์ด ํ์ฅ์ด ํ์ํ ๋์ฒด ๋ฌธ๋ฒ(dustypomerleau.rust-syntax)์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ์ฌ์ฉํฉ๋๋ค. Rust-analyzer์ ํจ๊ป ์ด ํ์ฅ์ ์ฌ์ฉํ๋ ค๋ฉด ๋ฐ์ด๋๋ฆฌ๋ฅผ ์๋์ผ๋ก ์ค์นํด์ผ ํ์ผ๋ฉฐ, ์ด๋ ๋ช ๋ฌ ๋์ ์ง์๋ ๋ ๋ค๋ฅธ ๋ฌธ์ ์ ๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ํ์ฅ ํ๋ก๊ทธ๋จ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ์ด๊ฒ์๋ ๋ถ๊ตฌํ๊ณ RLS๊ฐ ๋ฒ์ ๊ธฐ๋ณธ๊ฐ์ด ๋จ์๋ ๋ถ๊ตฌํ๊ณ ๋ น ๋ถ์๊ธฐ๊ฐ ์ด๋ฅผ ๋ฅ๊ฐํ ๊ฒ์ผ๋ก ๋ณด์ ๋๋ค.
@JKAnderson409 ๋ dustypomerleau.rust-syntax
๊ตฌ๋ฌธ์ด ์ต๊ทผ rust-analyzer
์ ๋ณํฉ๋์์์ ์ฃผ๋ชฉํฉ๋๋ค.
@JKAnderson409 ๋
dustypomerleau.rust-syntax
๊ตฌ๋ฌธ์ด ์ต๊ทผrust-analyzer
์ ๋ณํฉ๋์์์ ์ฃผ๋ชฉํฉ๋๋ค.
์, ์ข์ ์์์ด์์ต๋๋ค. ๋๋ ์ค์ ๋ก ๋ด๊ฐ ๋ค๋ฅธ ์๊ฒฌ์ ๋งํ ๊ฐ์ ๋ ์ ๋ณํฉ์ ์๋ํ๊ธฐ ์ํด Dustypomerleau์๊ฒ ์์ฒญ ํ์ต๋๋ค. ๋งค์ผ ๋ฌธ๋ฒ์ ๋ฎ์ด์ธ ํ์๊ฐ ์๊ธฐ ๋๋ฌธ์ Rust-analyzer์ ์ผ๊ฐ ๋ฆด๋ฆฌ์ค๋ฅผ ๋ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค. Rust-analyzer ํ์ฅ์ ์ด์ ์ ์ ์ ์ผํ Rust ํ์ฅ์ ๋๋ค.
Rust-analyzer ํ์ฅ์ด ํ๋ฅญํ TextMate ๋ฌธ๋ฒ๊ณผ ํจ๊ป ์ ๊ณต๋ ์ ์๋๋ก @dustypomerleau ๊ฐ ๊ฒํ ํ๋ก์ธ์ค๋ฅผ ์งํํ๋ ๋ฐ ๋ ธ๋ ฅ์ ๊ธฐ์ธ์ธ ๊ฒ์ ๊ฐ์ฌ๋๋ฆฝ๋๋ค.
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
์, ์ข์ ์์์ด์์ต๋๋ค. ๋๋ ์ค์ ๋ก ๋ด๊ฐ ๋ค๋ฅธ ์๊ฒฌ์ ๋งํ ๊ฐ์ ๋ ์ ๋ณํฉ์ ์๋ํ๊ธฐ ์ํด Dustypomerleau์๊ฒ ์์ฒญ ํ์ต๋๋ค. ๋งค์ผ ๋ฌธ๋ฒ์ ๋ฎ์ด์ธ ํ์๊ฐ ์๊ธฐ ๋๋ฌธ์ Rust-analyzer์ ์ผ๊ฐ ๋ฆด๋ฆฌ์ค๋ฅผ ๋ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค. Rust-analyzer ํ์ฅ์ ์ด์ ์ ์ ์ ์ผํ Rust ํ์ฅ์ ๋๋ค.
Rust-analyzer ํ์ฅ์ด ํ๋ฅญํ TextMate ๋ฌธ๋ฒ๊ณผ ํจ๊ป ์ ๊ณต๋ ์ ์๋๋ก @dustypomerleau ๊ฐ ๊ฒํ ํ๋ก์ธ์ค๋ฅผ ์งํํ๋ ๋ฐ ๋ ธ๋ ฅ์ ๊ธฐ์ธ์ธ ๊ฒ์ ๊ฐ์ฌ๋๋ฆฝ๋๋ค.