Skip to content

Commit 3ddd8f7

Browse files
authored
Add constant support for windows-rdl (#3882)
1 parent fe92024 commit 3ddd8f7

6 files changed

Lines changed: 129 additions & 3 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use super::*;
2+
3+
pub fn encode_const(encoder: &mut Encoder, item: &syntax::Const) -> Result<(), Error> {
4+
let name = item.name.to_string();
5+
let ty = encode_type(encoder, &item.ty)?;
6+
let value = encode_value(encoder, &ty, &item.expr)?;
7+
8+
let field = encoder.output.Field(
9+
&name,
10+
&ty,
11+
metadata::FieldAttributes::Public
12+
| metadata::FieldAttributes::Static
13+
| metadata::FieldAttributes::Literal,
14+
);
15+
16+
encoder
17+
.output
18+
.Constant(metadata::writer::HasConstant::Field(field), &value);
19+
20+
Ok(())
21+
}

crates/libs/rdl/src/reader/mod.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod r#const;
12
mod r#enum;
23
mod r#fn;
34
mod index;
@@ -10,6 +11,7 @@ use super::*;
1011
use index::*;
1112
use interface::*;
1213
use param::*;
14+
use r#const::*;
1315
use r#enum::*;
1416
use r#fn::*;
1517
use r#struct::*;
@@ -288,6 +290,7 @@ fn encode_item(
288290
syntax::Item::Interface(ty) => encode_interface(encoder, ty),
289291
syntax::Item::Union(ty) => encode_union(encoder, ty),
290292
syntax::Item::Fn(ty) => encode_fn(encoder, ty),
293+
syntax::Item::Const(ty) => encode_const(encoder, ty),
291294
rest => todo!("{rest:?}"),
292295
}
293296
}
@@ -301,6 +304,70 @@ fn encode_type(encoder: &Encoder, ty: &syn::Type) -> Result<metadata::Type, Erro
301304
}
302305
}
303306

307+
fn encode_value(
308+
encoder: &Encoder,
309+
ty: &metadata::Type,
310+
value: &syn::Expr,
311+
) -> Result<metadata::Value, Error> {
312+
let value = match ty {
313+
metadata::Type::I8 => metadata::Value::I8(encode_neg_lit_int::<i8>(encoder, value)?),
314+
metadata::Type::U8 => metadata::Value::U8(encode_lit_int::<u8>(encoder, value)?),
315+
metadata::Type::I16 => metadata::Value::I16(encode_neg_lit_int::<i16>(encoder, value)?),
316+
metadata::Type::U16 => metadata::Value::U16(encode_lit_int::<u16>(encoder, value)?),
317+
metadata::Type::I32 => metadata::Value::I32(encode_neg_lit_int::<i32>(encoder, value)?),
318+
metadata::Type::U32 => metadata::Value::U32(encode_lit_int::<u32>(encoder, value)?),
319+
metadata::Type::I64 => metadata::Value::I64(encode_neg_lit_int::<i64>(encoder, value)?),
320+
metadata::Type::U64 => metadata::Value::U64(encode_lit_int::<u64>(encoder, value)?),
321+
rest => todo!("{rest:?}"),
322+
};
323+
324+
Ok(value)
325+
}
326+
327+
fn encode_neg_lit_int<T>(encoder: &Encoder, expr: &syn::Expr) -> Result<T, Error>
328+
where
329+
T: std::str::FromStr + std::ops::Neg<Output = T>,
330+
T::Err: std::fmt::Display,
331+
{
332+
let value = match expr {
333+
syn::Expr::Lit(syn::ExprLit {
334+
lit: syn::Lit::Int(int),
335+
..
336+
}) => int.base10_parse().ok(),
337+
syn::Expr::Unary(syn::ExprUnary {
338+
op: syn::UnOp::Neg(_),
339+
expr,
340+
..
341+
}) => match expr.as_ref() {
342+
syn::Expr::Lit(syn::ExprLit {
343+
lit: syn::Lit::Int(int),
344+
..
345+
}) => int.base10_parse().ok().map(|value: T| -value),
346+
_ => None,
347+
},
348+
_ => None,
349+
};
350+
351+
value.ok_or_else(|| encoder.error(expr, "value not valid"))
352+
}
353+
354+
fn encode_lit_int<T>(encoder: &Encoder, expr: &syn::Expr) -> Result<T, Error>
355+
where
356+
T: std::str::FromStr,
357+
T::Err: std::fmt::Display,
358+
{
359+
let value = match expr {
360+
syn::Expr::Lit(syn::ExprLit {
361+
lit: syn::Lit::Int(int),
362+
..
363+
}) => int.base10_parse().ok(),
364+
365+
_ => None,
366+
};
367+
368+
value.ok_or_else(|| encoder.error(expr, "value not valid"))
369+
}
370+
304371
fn encode_type_reference(
305372
encoder: &Encoder,
306373
ty: &syn::TypeReference,

crates/libs/rdl/src/syntax/item.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ impl syn::parse::Parse for Item {
6666
input.parse().map(Item::Union)
6767
} else if lookahead.peek(syn::Token![fn]) {
6868
input.parse().map(Item::Fn)
69+
} else if lookahead.peek(syn::Token![const]) {
70+
input.parse().map(Item::Const)
6971
} else {
7072
Err(lookahead.error())
7173
}?;

crates/libs/rdl/src/writer/mod.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,12 +163,20 @@ fn rustfmt(tokens: &str) -> Option<String> {
163163
fn write(namespace: &str, item: &metadata::reader::Item) -> TokenStream {
164164
match item {
165165
metadata::reader::Item::Type(ty) => write_type_def(ty),
166-
metadata::reader::Item::Fn(ty) => write_method_def(namespace, ty),
167-
rest => todo!("{rest:?}"),
166+
metadata::reader::Item::Fn(ty) => write_fn(namespace, ty),
167+
metadata::reader::Item::Const(ty) => write_const(namespace, ty),
168168
}
169169
}
170170

171-
fn write_method_def(namespace: &str, item: &metadata::reader::MethodDef) -> TokenStream {
171+
fn write_const(namespace: &str, item: &metadata::reader::Field) -> TokenStream {
172+
let name = format_ident!("{}", item.name());
173+
let constant = item.constant().expect("field missing constant");
174+
let ty = write_type(namespace, &item.ty());
175+
let value = write_value(&constant.value());
176+
quote! { const #name: #ty = #value; }
177+
}
178+
179+
fn write_fn(namespace: &str, item: &metadata::reader::MethodDef) -> TokenStream {
172180
let name = format_ident!("{}", item.name());
173181
let signature = item.signature(&[]);
174182

crates/libs/rdl/tests/const.rdl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#[win32]
2+
mod Test {
3+
const I16: i16 = -16;
4+
const I32: i32 = -32;
5+
const I64: i64 = -64;
6+
const I8: i8 = -8;
7+
const U16: u16 = 16;
8+
const U32: u32 = 32;
9+
const U64: u64 = 64;
10+
const U8: u8 = 8;
11+
}

crates/libs/rdl/tests/const.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use windows_rdl::*;
2+
3+
#[test]
4+
pub fn parse() {
5+
Reader::new()
6+
.input("tests/const.rdl")
7+
.output("tests/const.winmd")
8+
.write()
9+
.unwrap();
10+
11+
Writer::new()
12+
.input("tests/const.winmd")
13+
.output("tests/const.rdl")
14+
.namespace("Test")
15+
.write()
16+
.unwrap();
17+
}

0 commit comments

Comments
 (0)