vfs: auto-implement Vnode using macros

This commit is contained in:
Mark Poliakov 2023-07-18 23:23:16 +03:00
parent 058bfddd58
commit 901f311856
6 changed files with 136 additions and 17 deletions

View File

@ -7,4 +7,5 @@ edition = "2021"
[dependencies]
yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" }
macros = { path = "macros" }
bitflags = "2.3.3"

16
lib/vfs/macros/Cargo.toml Normal file
View File

@ -0,0 +1,16 @@
[package]
name = "macros"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
proc-macro = true
[dependencies]
lazy_static = "1.4.0"
proc-macro-crate = "1.3.1"
proc-macro2 = "1.0.66"
quote = "1.0.31"
syn = { version = "2.0.26", features = ["full"] }

53
lib/vfs/macros/src/lib.rs Normal file
View File

@ -0,0 +1,53 @@
use std::collections::HashSet;
use proc_macro::TokenStream;
use proc_macro2::Ident;
use proc_macro_crate::{crate_name, FoundCrate};
use quote::{quote, ToTokens};
use syn::{parse_macro_input, ImplItem, ItemImpl};
mod vnode_impl;
use vnode_impl::IMPLS;
#[proc_macro_attribute]
pub fn auto_vnode_impl(attr: TokenStream, input: TokenStream) -> TokenStream {
let current_crate = crate_name("vfs").unwrap();
let vfs_crate = match current_crate {
FoundCrate::Itself => quote!(crate),
FoundCrate::Name(name) => quote!( #name ),
};
let mut impl_item = parse_macro_input!(input as ItemImpl);
let behavior = if attr.is_empty() {
"unimplemented".to_string()
} else {
parse_macro_input!(attr as Ident).to_string()
};
let behavior = match behavior.as_str() {
"unimplemented" => quote! { unimplemented!() },
"panic" => quote! { panic!() },
"error" => quote! { Err(yggdrasil_abi::error::Error::NotImplemented) },
_ => panic!("Unknown #[auto_vnode_impl] behavior: {:?}", behavior),
};
let mut missing_impls: HashSet<&str> = HashSet::from_iter(IMPLS.keys().copied());
for item in &impl_item.items {
match item {
ImplItem::Fn(f) => {
let name = &f.sig.ident.to_string();
missing_impls.remove(name.as_str());
}
_ => panic!("Unexpected item in Vnode impl"),
}
}
for &item in &missing_impls {
let f = IMPLS.get(item).unwrap();
let fn_impl = f(&vfs_crate, &behavior);
impl_item.items.push(ImplItem::Verbatim(fn_impl));
}
impl_item.to_token_stream().into()
}

View File

@ -0,0 +1,60 @@
use std::collections::HashMap;
use proc_macro2::TokenStream as TS2;
use quote::quote;
fn impl_open(vfs: &TS2, behavior: &TS2) -> TS2 {
quote! {
fn open(&mut self, _node: &#vfs::VnodeRef, _opts: yggdrasil_abi::io::OpenFlags)
-> Result<usize, yggdrasil_abi::error::Error> {
#behavior
}
}
}
fn impl_close(vfs: &TS2, behavior: &TS2) -> TS2 {
quote! {
fn close(&mut self, _node: &#vfs::VnodeRef) -> Result<(), Error> {
#behavior
}
}
}
fn impl_create(vfs: &TS2, behavior: &TS2) -> TS2 {
quote! {
fn create(&mut self, _at: &#vfs::VnodeRef, _name: &str, _kind: #vfs::VnodeKind)
-> Result<#vfs::VnodeRef, yggdrasil_abi::error::Error> {
#behavior
}
}
}
fn impl_write(vfs: &TS2, behavior: &TS2) -> TS2 {
quote! {
fn write(&mut self, _node: &#vfs::VnodeRef, _pos: usize, _data: &[u8])
-> Result<usize, yggdrasil_abi::error::Error> {
#behavior
}
}
}
fn impl_read(vfs: &TS2, behavior: &TS2) -> TS2 {
quote! {
fn read(&mut self, _node: &#vfs::VnodeRef, _pos: usize, _data: &mut [u8])
-> Result<usize, yggdrasil_abi::error::Error> {
#behavior
}
}
}
lazy_static::lazy_static! {
pub static ref IMPLS: HashMap<&'static str, fn(&TS2, &TS2) -> TS2> = {
let mut m = HashMap::new();
m.insert("open".into(), impl_open as _);
m.insert("close".into(), impl_close as _);
m.insert("create".into(), impl_create as _);
m.insert("write".into(), impl_write as _);
m.insert("read".into(), impl_read as _);
m
};
}

View File

@ -1,6 +1,7 @@
use yggdrasil_abi::error::Error;
use macros::auto_vnode_impl;
use yggdrasil_abi::{error::Error, io::OpenFlags};
use crate::node::{VnodeImpl, VnodeRef};
use crate::{node::VnodeImpl, VnodeRef};
pub trait CharDevice {
fn read(&'static self, blocking: bool, data: &mut [u8]) -> Result<usize, Error>;
@ -17,12 +18,9 @@ impl CharDeviceWrapper {
}
}
#[auto_vnode_impl(error)]
impl VnodeImpl for CharDeviceWrapper {
fn open(
&mut self,
_node: &VnodeRef,
_opts: yggdrasil_abi::io::OpenFlags,
) -> Result<usize, Error> {
fn open(&mut self, _node: &VnodeRef, _opts: OpenFlags) -> Result<usize, Error> {
Ok(0)
}
@ -37,13 +35,4 @@ impl VnodeImpl for CharDeviceWrapper {
fn write(&mut self, _node: &VnodeRef, _pos: usize, data: &[u8]) -> Result<usize, Error> {
self.device.write(true, data)
}
fn create(
&mut self,
_at: &VnodeRef,
_name: &str,
_kind: crate::node::VnodeKind,
) -> Result<VnodeRef, Error> {
todo!()
}
}

View File

@ -4,7 +4,7 @@ use core::time::Duration;
use abi::{
error::{Error, IntoSyscallResult},
io::{OpenFlags, RawFd},
SyscallFunction,
syscall::SyscallFunction,
};
use vfs::{Read, Write};