Derived Serialize for some syn structures needed and moved some files around.

This commit is contained in:
Thelie 2022-02-28 23:19:21 +01:00
parent ca6ebc1805
commit be39277042
8 changed files with 483 additions and 45 deletions

View file

@ -1,16 +1,17 @@
[workspace]
members = [
"sing_derive",
"sing_macros",
"sing_parse",
"sing_util",
]
# [package]
# name = "sing"
# version = "0.1.0"
# edition = "2021"
#
# [lib]
# bench = false
[package]
name = "sing"
version = "0.1.0"
edition = "2021"
[lib]
bench = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
# build = "build.rs"
@ -18,8 +19,7 @@ members = [
# [build-dependencies]
# lalrpop = "0.19"
#
# [dependencies]
# syn = "1"
# regex = "1"
# lalrpop-util = "0.19"
# lalrpop = "0.19"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
syn = { version = "1.0", features = ["full"] }

View file

@ -1,27 +0,0 @@
use std::{collections::HashMap, io::Read, fmt::Write};
struct TraitProfile{}
struct FunctionProfile{}
struct Evaluator <R: Read, W: Write, T>{
traits: HashMap<String, TraitProfile>,
functions: HashMap<String, FunctionProfile>,
input: R,
output: W,
err: W,
worker: T
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
let result = 2 + 2;
assert_eq!(result, 4);
}
}

18
sing_macros/Cargo.toml Normal file
View file

@ -0,0 +1,18 @@
[package]
name = "sing_derive"
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]
sing_util = { path = "../sing_util" }
proc-macro2 = "1.0"
ron = "0.7"
rand = "0.7"
serde = { version = "1.0", features = ["derive"] }
syn = { version = "1.0", features = ["full"] }
quote = "1.0"

102
sing_macros/src/lib.rs Normal file
View file

@ -0,0 +1,102 @@
use std::{
collections::HashMap,
env,
fs,
error::Error,
io::{Write, Read}, fmt::format, path::Path,
};
use rand::rngs::adapter::ReseedingRng;
use serde::{Serialize, Deserialize};
use syn::{parse_macro_input, DeriveInput, AttributeArgs, ItemImpl, ImplItem};
use quote::{quote, spanned::Spanned};
use proc_macro2::{Span, Spacing, Delimiter, TokenStream, Literal, TokenTree, Ident, Punct, Group};
extern crate sing_util;
extern crate proc_macro;
fn get_run_id () -> Result<usize, Box<dyn Error>> {
// Get a random uid for this compiler run and save it as an environment variable.
// Load it if it's already there.
match env::var("COMP_RUN_ID") {
Ok(v) => Ok(v.parse()?),
Err(_) => {
let id: usize = rand::random();
let id_str = format!("{}", id);
env::set_var("COMP_RUN_ID", id_str);
Ok(id)
}
}
}
fn get_state_file_path() -> Result<String, Box<dyn Error>> {
let compilation_run_identifier = get_run_id()?;
Ok(format!("/tmp/sing-trait-store-{}", compilation_run_identifier))
}
fn save_trait_state(map: HashMap<String, sing_util::TraitProfile>) -> Result<usize, Box<dyn Error>> {
let state_file_path = get_state_file_path()?;
let mut state_file = fs::File::create(state_file_path)?;
let state_string = ron::to_string(&map)?;
Ok(state_file.write(state_string.as_bytes())?)
}
fn load_trait_state() -> Result<HashMap<String, sing_util::TraitProfile>, Box<dyn Error>> {
let stat_file_path = get_state_file_path()?;
let mut state_file = fs::File::open(stat_file_path)?;
let mut state_string= String::from("");
state_file.read_to_string(&mut state_string)?;
Ok(ron::from_str(&state_string)?)
}
#[proc_macro_attribute]
pub fn my_derive(input: proc_macro::TokenStream, annotated_item: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as ItemImpl);
let annotated_item = parse_macro_input!(annotated_item as AttributeArgs);
let trait_name;
match input.trait_ {
Some((_b, p, _f)) => {
trait_name = p;
},
None => {
syn::Error::new(input.__span(), "This attribute can only be used on trait impl blocks.")
.to_compile_error();
},
};
let mut trait_functions = vec!();
for fun in input.items {
match fun {
ImplItem::Method(m) => trait_functions.push(m.sig),
_ => {
syn::Error::new(input.__span(), "Found unexpected item that is not a method.")
.to_compile_error();
},
}
}
let trait_state = load_trait_state().unwrap();
save_trait_state(trait_state).unwrap();
// Build the output, possibly using quasi-quotation
let output = quote! {
// ...
};
proc_macro::TokenStream::from(output)
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
let result = 2 + 2;
assert_eq!(result, 4);
}
}

View file

@ -1,12 +1,12 @@
[package]
name = "sing_derive"
name = "sing_util"
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]
ron = "0.7"
rand = "0.7"
serde = { version = "1.0", features = ["derive"] }

70
sing_util/src/lib.rs Normal file
View file

@ -0,0 +1,70 @@
use std::{
collections::HashMap,
env,
fs,
error::Error,
io::{Write, Read}, fmt::format,
};
use rand::rngs::adapter::ReseedingRng;
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FunctionProfile{
inputs: String,
outputs: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TraitProfile{
functions: HashMap<String, FunctionProfile>,
}
impl TraitProfile {
pub fn get_fun_profile(&self, query: &String) -> Option<&FunctionProfile> {
self.functions.get(query)
}
}
#[derive(Debug, Clone)]
enum DeduplicatedFunctionProfile {
Single(String, FunctionProfile),
Multiple(Vec<String>, FunctionProfile),
}
/*impl<T> Evaluator<T> {
fn deduplicate_functions(&self) -> Self<T> {
let mut self = self.clone();
let mut functions: HashMap<String, DeduplicatedFunctionProfile>;
for (t_name, t_profile) in self.traits {
for (fun_name, fun_profile) in t_profile.functions {
if !functions.contains_key(fun_name) {
self.functions.insert(fun_name, DeduplicatedFunctionProfile::Single(t_name, fun_profile))
} else {
let other = self.functions.remove(fun_name).unwrap();
let traits: Vec<String>;
match other {
DeduplicatedFunctionProfile::Single(t, _) => traits = vec!(t),
DeduplicatedFunctionProfile::Multiple(ts, _) => traits = ts,
}
self.functions.insert(fun_name, DeduplicatedFunctionProfile::Multiple(traits, fun_profile))
}
}
}
}
}
*/
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
let result = 2 + 2;
assert_eq!(result, 4);
}
}

55
src/lib.rs Normal file
View file

@ -0,0 +1,55 @@
use core::fmt::Debug;
use serde::{Serialize, Deserialize};
use serde_wrapper::ImplItemMethodWrapper;
mod serde_wrapper;
#[derive(Debug, Clone, Serialize, Deserialize)]
struct TraitProfile{
//functions: HashMap<String, FunctionProfile>,
functions: Vec<ImplItemMethodWrapper>,
}
#[derive(Debug, Clone)]
enum DeduplicatedFunctionProfile {
Single(String, ImplItemMethodWrapper),
Multiple(Vec<String>, ImplItemMethodWrapper),
}
/*impl<T> Evaluator<T> {
fn deduplicate_functions(&self) -> Self<T> {
let mut self = self.clone();
let mut functions: HashMap<String, DeduplicatedFunctionProfile>;
for (t_name, t_profile) in self.traits {
for (fun_name, fun_profile) in t_profile.functions {
if !functions.contains_key(fun_name) {
self.functions.insert(fun_name, DeduplicatedFunctionProfile::Single(t_name, fun_profile))
} else {
let other = self.functions.remove(fun_name).unwrap();
let traits: Vec<String>;
match other {
DeduplicatedFunctionProfile::Single(t, _) => traits = vec!(t),
DeduplicatedFunctionProfile::Multiple(ts, _) => traits = ts,
}
self.functions.insert(fun_name, DeduplicatedFunctionProfile::Multiple(traits, fun_profile))
}
}
}
}
}
*/
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
let result = 2 + 2;
assert_eq!(result, 4);
}
}

220
src/serde_wrapper.rs Normal file
View file

@ -0,0 +1,220 @@
use serde::{Serialize, Deserialize, Serializer, Deserializer, ser::SerializeStruct};
use syn::{ImplItemMethod, Visibility, Signature, Pat, FnArg, Type, PatIdent, Ident, __private::Span, Receiver, ReturnType, Generics};
use core::fmt::{Debug, Formatter};
use std::error::Error;
#[derive(Clone)]
pub (crate) struct ImplItemMethodWrapper(ImplItemMethod);
impl Debug for ImplItemMethodWrapper {
fn fmt(&self, _: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
todo!()
}
}
impl Serialize for ImplItemMethodWrapper {
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where
S: Serializer
{
let inner = &self.0;
let mut state = serializer.serialize_struct("Color", 4)?;
// Attribute macros are not important in our case.
state.serialize_field("vis", &VisibilityWrapper(&inner.vis));
// Defaultness are also not important here.
state.serialize_field("sig", &SignatureWrapper(&inner.sig));
// We can throw away the block too.
state.end()
}
}
impl<'de> Deserialize<'de> for ImplItemMethodWrapper {
fn deserialize<D>(_: D) -> Result<Self, <D as Deserializer<'de>>::Error> where D: Deserializer<'de> {
todo!()
}
}
struct VisibilityWrapper<'a>(&'a Visibility);
impl Serialize for VisibilityWrapper<'_> {
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where
S: Serializer
{
match &self.0 {
Visibility::Public(_) => serializer.serialize_str("pub"),
Visibility::Crate(_) => serializer.serialize_str("crate"),
Visibility::Restricted(r) => {
let mut path_str = String::from("");
for seg in &r.path.segments {
// There should be no arguments in the paths passed here.
path_str.push_str(seg.ident.to_string().as_str());
path_str.push_str("::");
}
serializer.serialize_str(
format!("pub ({})", path_str).as_str()
)
},
Visibility::Inherited => serializer.serialize_str("inherited"),
}
}
}
struct SignatureWrapper<'a>(&'a Signature);
impl Serialize for SignatureWrapper<'_> {
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where
S: Serializer
{
let inner = &self.0;
let mut state = serializer.serialize_struct("Signature", 7)?;
let mut prefixes = vec!();
if inner.constness.is_some() {
prefixes.push("const")
}
if inner.asyncness.is_some() {
prefixes.push("async")
}
if inner.unsafety.is_some() {
prefixes.push("unsafe")
}
state.serialize_field("prefixes", &prefixes)?;
match &inner.abi {
Some(a) => state.serialize_field(
"abi",
&Some(
format!(
"extern {}",
match &a.name {
Some(n) => n.value(),
None => String::from(""),
}
).as_str()
)
),
None => state.serialize_field("abi", &None::<String>),
}?;
// No need to serialize the Fn token
state.serialize_field("ident", &inner.ident.to_string());
state.serialize_field("generics", &GenericsWrapper(&inner.generics));
// Parentheses do not need to be serialized either
serialize_iterator(
&mut state,
Box::new(inner
.inputs
.clone()
.into_iter()
),
"inputs",
| inp: &FnArg | -> Result<(PatWrapper, Option<TypeWrapper>), Box<dyn Error>> {
match inp {
FnArg::Receiver(r) => Ok(patopt_from_receiver(r.clone())),
FnArg::Typed(t) => Ok((PatWrapper(*t.pat.clone()), Some(TypeWrapper(*t.ty.clone())))),
}
}
);
state.serialize_field("variadic", match inner.variadic{
Some(_) => "...",
None => "",
});
match &inner.output{
ReturnType::Default => {state.serialize_field("output", "()");},
ReturnType::Type(_, t) => {(state.serialize_field("output", &TypeWrapper(*t.clone())));}
};
state.end()
}
}
struct GenericsWrapper<'a>(&'a Generics);
impl Serialize for GenericsWrapper<'_> {
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where
S: Serializer
{
todo!()
}
}
struct PatWrapper(Pat);
impl Serialize for PatWrapper {
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where
S: Serializer
{
todo!()
}
}
struct TypeWrapper( Type);
impl Serialize for TypeWrapper {
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where
S: Serializer
{
todo!()
}
}
fn patopt_from_receiver(r: Receiver) -> (PatWrapper, Option<TypeWrapper>) {
let mut ident = String::from("");
match &r.reference {
Some((_, lt)) => {
ident.push_str("&");
match lt {
Some(l) => ident.push_str(
&l.ident
.to_string()
.as_str()
),
None => {},
}
ident.push_str(" ");
},
None => {},
}
(PatWrapper(Pat::Ident(PatIdent{
attrs: vec!(),
by_ref: None,
mutability: r.mutability,
ident: Ident::new(&ident, Span::call_site()),
subpat: None,
})), None)
}
fn serialize_iterator<S, T, F, U> (serializer: &mut S, iterator: Box<dyn Iterator<Item = T>>, field_name: &'static str, get_string_fun: F)
-> Result<(), Box<dyn Error>>
where
F: Fn(&T) -> Result<U, Box<dyn Error>>,
S: SerializeStruct,
U: Serialize,
{
let mut p_vec = vec!();
for item in iterator {
p_vec.push(get_string_fun(&item)?);
}
serializer.serialize_field(field_name, &p_vec);
Ok(())
}