Skip to content

Commit

Permalink
Refactoring of schemars_derive
Browse files Browse the repository at this point in the history
  • Loading branch information
GREsau committed Dec 9, 2019
1 parent dca9e2d commit 3fb625e
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 138 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use syn::{Attribute, Lit::Str, Meta::NameValue, MetaNameValue};

pub fn get_title_and_desc_from_docs(attrs: &[Attribute]) -> (Option<String>, Option<String>) {
let docs = match get_docs(attrs) {
pub fn get_title_and_desc_from_doc(attrs: &[Attribute]) -> (Option<String>, Option<String>) {
let doc = match get_doc(attrs) {
None => return (None, None),
Some(docs) => docs,
Some(doc) => doc,
};

if docs.starts_with('#') {
let mut split = docs.splitn(2, '\n');
if doc.starts_with('#') {
let mut split = doc.splitn(2, '\n');
let title = split
.next()
.unwrap()
Expand All @@ -17,12 +17,12 @@ pub fn get_title_and_desc_from_docs(attrs: &[Attribute]) -> (Option<String>, Opt
let maybe_desc = split.next().and_then(merge_description_lines);
(none_if_empty(title), maybe_desc)
} else {
(None, merge_description_lines(&docs))
(None, merge_description_lines(&doc))
}
}

fn merge_description_lines(docs: &str) -> Option<String> {
let desc = docs
fn merge_description_lines(doc: &str) -> Option<String> {
let desc = doc
.trim()
.split("\n\n")
.filter_map(|line| none_if_empty(line.trim().replace('\n', " ")))
Expand All @@ -31,8 +31,8 @@ fn merge_description_lines(docs: &str) -> Option<String> {
none_if_empty(desc)
}

fn get_docs(attrs: &[Attribute]) -> Option<String> {
let docs = attrs
fn get_doc(attrs: &[Attribute]) -> Option<String> {
let doc = attrs
.iter()
.filter_map(|attr| {
if !attr.path.is_ident("doc") {
Expand All @@ -53,7 +53,7 @@ fn get_docs(attrs: &[Attribute]) -> Option<String> {
.skip_while(|s| *s == "")
.collect::<Vec<_>>()
.join("\n");
none_if_empty(docs)
none_if_empty(doc)
}

fn none_if_empty(s: String) -> Option<String> {
Expand Down
71 changes: 71 additions & 0 deletions schemars_derive/src/attr/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
mod doc;
mod schemars_to_serde;

pub use doc::get_title_and_desc_from_doc;
pub use schemars_to_serde::process_serde_attrs;

use proc_macro2::{Group, Span, TokenStream, TokenTree};
use syn::parse::{self, Parse};

pub fn get_with_from_attrs(field: &syn::Field) -> Option<syn::Result<syn::ExprPath>> {
field
.attrs
.iter()
.filter(|at| match at.path.get_ident() {
// FIXME this is relying on order of attributes (schemars before serde) from preprocess.rs
Some(i) => i == "schemars" || i == "serde",
None => false,
})
.filter_map(get_with_from_attr)
.next()
.map(|lit| parse_lit_str(&lit))
}

fn get_with_from_attr(attr: &syn::Attribute) -> Option<syn::LitStr> {
use syn::*;
let nested_metas = match attr.parse_meta() {
Ok(Meta::List(meta)) => meta.nested,
_ => return None,
};
for nm in nested_metas {
if let NestedMeta::Meta(Meta::NameValue(MetaNameValue {
path,
lit: Lit::Str(with),
..
})) = nm
{
if path.is_ident("with") {
return Some(with);
}
}
}
None
}

fn parse_lit_str<T>(s: &syn::LitStr) -> parse::Result<T>
where
T: Parse,
{
let tokens = spanned_tokens(s)?;
syn::parse2(tokens)
}

fn spanned_tokens(s: &syn::LitStr) -> parse::Result<TokenStream> {
let stream = syn::parse_str(&s.value())?;
Ok(respan_token_stream(stream, s.span()))
}

fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
stream
.into_iter()
.map(|token| respan_token_tree(token, span))
.collect()
}

fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
if let TokenTree::Group(g) = &mut token {
*g = Group::new(g.delimiter(), respan_token_stream(g.stream(), span));
}
token.set_span(span);
token
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use quote::ToTokens;
use serde_derive_internals::Ctxt;
use std::collections::HashSet;
use syn::parse::Parser;
use syn::{Attribute, Data, DeriveInput, Field, GenericParam, Generics, Meta, NestedMeta, Variant};
use syn::{Attribute, Data, Field, Meta, NestedMeta, Variant};

// List of keywords that can appear in #[serde(...)]/#[schemars(...)] attributes which we want serde_derive_internals to parse for us.
static SERDE_KEYWORDS: &[&str] = &[
Expand All @@ -28,17 +28,9 @@ static SERDE_KEYWORDS: &[&str] = &[
"with",
];

pub fn add_trait_bounds(generics: &mut Generics) {
for param in &mut generics.params {
if let GenericParam::Type(ref mut type_param) = *param {
type_param.bounds.push(parse_quote!(schemars::JsonSchema));
}
}
}

// If a struct/variant/field has any #[schemars] attributes, then create copies of them
// as #[serde] attributes so that serde_derive_internals will parse them for us.
pub fn process_serde_attrs(input: &mut DeriveInput) -> Result<(), Vec<syn::Error>> {
pub fn process_serde_attrs(input: &mut syn::DeriveInput) -> Result<(), Vec<syn::Error>> {
let ctxt = Ctxt::new();
process_attrs(&ctxt, &mut input.attrs);
match input.data {
Expand Down
Loading

0 comments on commit 3fb625e

Please sign in to comment.