Skip to content

Commit

Permalink
Ongoing metadata writer improvements and new command line tool (#2319)
Browse files Browse the repository at this point in the history
  • Loading branch information
kennykerr authored Feb 2, 2023
1 parent ad0da01 commit 86bfc0d
Show file tree
Hide file tree
Showing 15 changed files with 435 additions and 58 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/clippy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ jobs:
>> $env:GITHUB_ENV
- name: Run cargo clippy
run: |
cargo clippy -p riddle -- -A clippy::uninlined_format_args &&
cargo clippy -p sample_bits -- -A clippy::uninlined_format_args &&
cargo clippy -p sample_com_uri -- -A clippy::uninlined_format_args &&
cargo clippy -p sample_consent -- -A clippy::uninlined_format_args &&
Expand Down Expand Up @@ -102,6 +103,7 @@ jobs:
cargo clippy -p test_reserved -- -A clippy::uninlined_format_args &&
cargo clippy -p test_resources -- -A clippy::uninlined_format_args &&
cargo clippy -p test_return_struct -- -A clippy::uninlined_format_args &&
cargo clippy -p test_riddle -- -A clippy::uninlined_format_args &&
cargo clippy -p test_simple_component -- -A clippy::uninlined_format_args &&
cargo clippy -p test_string_param -- -A clippy::uninlined_format_args &&
cargo clippy -p test_structs -- -A clippy::uninlined_format_args &&
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ jobs:
}
- name: Test
run: >
cargo test --target ${{ matrix.target }} -p riddle &&
cargo test --target ${{ matrix.target }} -p sample_bits &&
cargo test --target ${{ matrix.target }} -p sample_com_uri &&
cargo test --target ${{ matrix.target }} -p sample_consent &&
Expand Down Expand Up @@ -152,6 +153,7 @@ jobs:
cargo test --target ${{ matrix.target }} -p test_reserved &&
cargo test --target ${{ matrix.target }} -p test_resources &&
cargo test --target ${{ matrix.target }} -p test_return_struct &&
cargo test --target ${{ matrix.target }} -p test_riddle &&
cargo test --target ${{ matrix.target }} -p test_simple_component &&
cargo test --target ${{ matrix.target }} -p test_string_param &&
cargo test --target ${{ matrix.target }} -p test_structs &&
Expand Down
Original file line number Diff line number Diff line change
@@ -1,42 +1,4 @@
macro_rules! flags {
($name:ident, $size:ty) => {
#[derive(Default, Copy, Clone, PartialEq, Eq)]
pub struct $name(pub $size);
impl $name {
pub fn contains(&self, contains: Self) -> bool {
*self & contains == contains
}
}
impl std::ops::BitOr for $name {
type Output = Self;
fn bitor(self, other: Self) -> Self {
Self(self.0 | other.0)
}
}
impl std::ops::BitAnd for $name {
type Output = Self;
fn bitand(self, other: Self) -> Self {
Self(self.0 & other.0)
}
}
impl std::ops::BitOrAssign for $name {
fn bitor_assign(&mut self, other: Self) {
self.0.bitor_assign(other.0)
}
}
impl std::ops::BitAndAssign for $name {
fn bitand_assign(&mut self, other: Self) {
self.0.bitand_assign(other.0)
}
}
impl std::ops::Not for $name {
type Output = Self;
fn not(self) -> Self {
Self(self.0.not())
}
}
};
}
use super::*;

flags!(FieldAttributes, u16);
impl FieldAttributes {
Expand All @@ -49,17 +11,22 @@ impl FieldAttributes {
pub const HAS_DEFAULT: Self = Self(0x8000);
}

flags!(MethodAttributes, usize);
flags!(MethodAttributes, u16);
impl MethodAttributes {
pub const ABSTRACT: Self = Self(0x400);
pub const HIDE_BY_SIG: Self = Self(0x80);
pub const NEW_SLOT: Self = Self(0x100);
pub const PUBLIC: Self = Self(0x6);
pub const SPECIAL: Self = Self(0x800);
pub const VIRTUAL: Self = Self(0x40);
}

flags!(MethodImplAttributes, usize);
impl MethodImplAttributes {
pub const PRESERVE_SIG: Self = Self(0x80);
}

flags!(ParamAttributes, usize);
flags!(ParamAttributes, u16);
impl ParamAttributes {
pub const INPUT: Self = Self(0x1);
pub const OUTPUT: Self = Self(0x2);
Expand All @@ -84,4 +51,5 @@ impl TypeAttributes {
pub const SEALED: Self = Self(0x100);
pub const WINRT: Self = Self(0x4000);
pub const INTERFACE: Self = Self(0x20);
pub const SEQUENTIAL_LAYOUT: Self = Self(0x8);
}
46 changes: 44 additions & 2 deletions crates/libs/metadata/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,57 @@
#![allow(dead_code)]

use std::collections::*;
mod attributes;
mod bindings;
mod flags;
mod imp;
pub mod reader;
pub mod writer;

pub use attributes::*;
use bindings::*;
pub use flags::*;
use imp::*;
use std::io::*;
use std::mem::*;
use std::ptr::*;

macro_rules! flags {
($name:ident, $size:ty) => {
#[derive(Default, Copy, Clone, PartialEq, Eq)]
pub struct $name(pub $size);
impl $name {
pub fn contains(&self, contains: Self) -> bool {
*self & contains == contains
}
}
impl std::ops::BitOr for $name {
type Output = Self;
fn bitor(self, other: Self) -> Self {
Self(self.0 | other.0)
}
}
impl std::ops::BitAnd for $name {
type Output = Self;
fn bitand(self, other: Self) -> Self {
Self(self.0 & other.0)
}
}
impl std::ops::BitOrAssign for $name {
fn bitor_assign(&mut self, other: Self) {
self.0.bitor_assign(other.0)
}
}
impl std::ops::BitAndAssign for $name {
fn bitand_assign(&mut self, other: Self) {
self.0.bitand_assign(other.0)
}
}
impl std::ops::Not for $name {
type Output = Self;
fn not(self) -> Self {
Self(self.0.not())
}
}
};
}

pub(crate) use flags;
4 changes: 2 additions & 2 deletions crates/libs/metadata/src/reader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ impl<'a> Reader<'a> {
MethodImplAttributes(self.row_usize(row.0, 1))
}
pub fn method_def_flags(&self, row: MethodDef) -> MethodAttributes {
MethodAttributes(self.row_usize(row.0, 2))
MethodAttributes(self.row_usize(row.0, 2) as _)
}
pub fn method_def_name(&self, row: MethodDef) -> &str {
self.row_str(row.0, 3)
Expand Down Expand Up @@ -727,7 +727,7 @@ impl<'a> Reader<'a> {
//

pub fn param_flags(&self, row: Param) -> ParamAttributes {
ParamAttributes(self.row_usize(row.0, 0))
ParamAttributes(self.row_usize(row.0, 0) as _)
}
pub fn param_sequence(&self, row: Param) -> usize {
self.row_usize(row.0, 1)
Expand Down
64 changes: 58 additions & 6 deletions crates/libs/metadata/src/writer/imp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub fn round(size: usize, round: usize) -> usize {

pub fn write(name: &str, winrt: bool, definitions: &[Item], assemblies: &[&str]) -> Vec<u8> {
// Index assemblies used to resolve references to existing winmd files.
let assemblies = reader::File::with_default(assemblies).expect("Assemblies could not be loaded");
let assemblies: Vec<reader::File> = assemblies.iter().map(|file| reader::File::new(file).expect("Assemblies could not be loaded")).collect();
let assemblies = &reader::Reader::new(&assemblies);

// Build sorted list of definitions.
Expand Down Expand Up @@ -82,6 +82,13 @@ pub fn write(name: &str, winrt: bool, definitions: &[Item], assemblies: &[&str])
Item::Interface(ty) => {
strings.insert(&ty.namespace);
strings.insert(&ty.name);
ty.methods.iter().for_each(|method| {
strings.insert(&method.name);
blobs.insert(method_blob(method, definitions, references));
method.params.iter().for_each(|param| {
strings.insert(&param.name);
});
});
}
}
}
Expand All @@ -101,7 +108,7 @@ pub fn write(name: &str, winrt: bool, definitions: &[Item], assemblies: &[&str])
for (_index, item) in definitions.iter() {
match item {
Item::Struct(ty) => {
let mut flags = TypeAttributes::PUBLIC;
let mut flags = TypeAttributes::PUBLIC | TypeAttributes::SEQUENTIAL_LAYOUT | TypeAttributes::SEALED;
if winrt {
flags |= TypeAttributes::WINRT;
}
Expand All @@ -111,7 +118,7 @@ pub fn write(name: &str, winrt: bool, definitions: &[Item], assemblies: &[&str])
TypeNamespace: strings.index(&ty.namespace),
Extends: TypeDefOrRef::TypeRef(value_type).encode(),
FieldList: tables.Field.len() as _,
MethodList: 0,
MethodList: tables.MethodDef.len() as _,
});
for field in &ty.fields {
let flags = FieldAttributes::PUBLIC;
Expand All @@ -129,7 +136,7 @@ pub fn write(name: &str, winrt: bool, definitions: &[Item], assemblies: &[&str])
TypeNamespace: strings.index(&ty.namespace),
Extends: TypeDefOrRef::TypeRef(enum_type).encode(),
FieldList: tables.Field.len() as _,
MethodList: 0,
MethodList: tables.MethodDef.len() as _,
});
let enum_type = Type::named(&ty.namespace, &ty.name);
let flags = FieldAttributes::PRIVATE | FieldAttributes::SPECIAL | FieldAttributes::RUNTIME_SPECIAL;
Expand All @@ -145,11 +152,32 @@ pub fn write(name: &str, winrt: bool, definitions: &[Item], assemblies: &[&str])
}
}
Item::Interface(ty) => {
let mut flags = TypeAttributes::PUBLIC | TypeAttributes::INTERFACE;
let mut flags = TypeAttributes::PUBLIC | TypeAttributes::INTERFACE | TypeAttributes::ABSTRACT;
if winrt {
flags |= TypeAttributes::WINRT;
}
tables.TypeDef.push(tables::TypeDef { Flags: flags.0, TypeName: strings.index(&ty.name), TypeNamespace: strings.index(&ty.namespace), Extends: 0, FieldList: 0, MethodList: 0 });
tables.TypeDef.push(tables::TypeDef {
Flags: flags.0,
TypeName: strings.index(&ty.name),
TypeNamespace: strings.index(&ty.namespace),
Extends: 0,
FieldList: tables.Field.len() as _,
MethodList: tables.MethodDef.len() as _,
});
for method in &ty.methods {
let flags = MethodAttributes::ABSTRACT | MethodAttributes::HIDE_BY_SIG | MethodAttributes::NEW_SLOT | MethodAttributes::PUBLIC | MethodAttributes::VIRTUAL;
tables.MethodDef.push(tables::MethodDef {
RVA: 0,
ImplFlags: 0,
Flags: flags.0,
Name: strings.index(&method.name),
Signature: blobs.index(&method_blob(method, definitions, references)),
ParamList: tables.Param.len() as _,
});
for (sequence, param) in method.params.iter().enumerate() {
tables.Param.push(tables::Param { Flags: param_flags_to_attributes(param.flags).0, Sequence: (sequence + 1) as _, Name: strings.index(&param.name) });
}
}
}
}
}
Expand All @@ -174,6 +202,20 @@ fn type_reference<'a>(ty: &'a Type, definitions: &StagedDefinitions, assemblies:
}
}

fn param_flags_to_attributes(flags: ParamFlags) -> ParamAttributes {
let mut attributes = ParamAttributes(0);
if flags.contains(ParamFlags::INPUT) {
attributes |= ParamAttributes::INPUT;
}
if flags.contains(ParamFlags::OUTPUT) {
attributes |= ParamAttributes::OUTPUT;
}
if flags.contains(ParamFlags::OPTIONAL) {
attributes |= ParamAttributes::OPTIONAL;
}
attributes
}

fn item_type_name(item: &Item) -> (&str, &str) {
match item {
Item::Struct(ty) => (ty.namespace.as_str(), ty.name.as_str()),
Expand All @@ -189,6 +231,16 @@ fn item_value_type(item: &Item) -> bool {
}
}

fn method_blob(method: &Method, definitions: &StagedDefinitions, references: &StagedReferences) -> Vec<u8> {
let mut blob = vec![0x20]; // HASTHIS
u32_blob(method.params.len() as _, &mut blob);
for param in &method.params {
type_blob(&param.ty, &mut blob, definitions, references);
}
type_blob(&method.return_type, &mut blob, definitions, references);
blob
}

fn field_blob(ty: &Type, definitions: &StagedDefinitions, references: &StagedReferences) -> Vec<u8> {
let mut blob = vec![0x6];
type_blob(ty, &mut blob, definitions, references);
Expand Down
17 changes: 13 additions & 4 deletions crates/libs/metadata/src/writer/imp/tables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,11 +248,20 @@ impl Tables {
buffer.write_u32(x.Signature);
}

// for x in self.MethodDef {

// }
for x in self.MethodDef {
buffer.write_u32(x.RVA);
buffer.write_u16(x.ImplFlags);
buffer.write_u16(x.Flags);
buffer.write_u32(x.Name);
buffer.write_u32(x.Signature);
buffer.write_index(x.ParamList, self.Param.len());
}

// for x in self.Param {}
for x in self.Param {
buffer.write_u16(x.Flags);
buffer.write_u16(x.Sequence);
buffer.write_u32(x.Name);
}

for x in self.Constant {
buffer.write_u16(x.Type);
Expand Down
38 changes: 38 additions & 0 deletions crates/libs/metadata/src/writer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ impl Enum {
pub struct Interface {
pub namespace: String,
pub name: String,
pub methods: Vec<Method>,
}

impl Interface {
pub fn item(namespace: &str, name: &str, methods: Vec<Method>) -> Item {
Item::Interface(Self { namespace: namespace.to_string(), name: name.to_string(), methods })
}
}

pub struct Field {
Expand All @@ -63,6 +70,37 @@ impl Constant {
}
}

pub struct Method {
pub name: String,
pub return_type: Type,
pub params: Vec<Param>,
}

impl Method {
pub fn new(name: &str, return_type: Type, params: Vec<Param>) -> Self {
Self { name: name.to_string(), return_type, params }
}
}

pub struct Param {
pub name: String,
pub ty: Type,
pub flags: ParamFlags,
}

impl Param {
pub fn new(name: &str, ty: Type, flags: ParamFlags) -> Self {
Self { name: name.to_string(), ty, flags }
}
}

flags!(ParamFlags, u32);
impl ParamFlags {
pub const INPUT: Self = Self(0x1);
pub const OUTPUT: Self = Self(0x2);
pub const OPTIONAL: Self = Self(0x10);
}

pub enum Type {
Void,
Bool,
Expand Down
Loading

0 comments on commit 86bfc0d

Please sign in to comment.