Skip to content

Commit

Permalink
Merge pull request #3 from Trisfald/json
Browse files Browse the repository at this point in the history
Json
  • Loading branch information
Trisfald authored Feb 18, 2021
2 parents 444d5ef + b3ba89f commit f8f0842
Show file tree
Hide file tree
Showing 33 changed files with 1,116 additions and 245 deletions.
10 changes: 4 additions & 6 deletions .github/workflows/rust.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ name: Rust

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

Expand Down Expand Up @@ -37,14 +36,13 @@ jobs:
command: clippy
args: --tests --all-targets --all-features -- -D warnings

- name: Run cargo build
- name: Run cargo test
uses: actions-rs/cargo@v1
with:
command: build
args: --all-targets --all-features
command: test

- name: Run cargo test
- name: Run cargo test (json)
uses: actions-rs/cargo@v1
with:
command: test
args: --all-features
args: --features "json"
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.2.0]
### Added
- Option to enable json content type for all requests.

### Fixed
- All generated methods are now `pub`.

## [0.1.1] - 2021-02-11
### Fixed
- Re-export of libraries so users don't have to include them in their `Cargo.toml`.
Expand Down
21 changes: 20 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,33 @@ include = [
"src/**/*",
]

[features]
default = []
json = ["serde_json", "choices-derive/json"]

[dependencies]
choices-derive = { path = "choices-derive", version = "=0.1.1" }
async-trait = "0.1"
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
warp = "0.3"
bytes = "1.0"
serde_json = { version = "1.0", optional = true }

[dev-dependencies]
util = { path = "utilities" }
lazy_static = "1.4"
reqwest = "0.11"
rand = "0.8"
serde = { version = "1.0", features = ["derive"] }

[[example]]
name = "json"
required-features = ["json"]

[[example]]
name = "user_type_json"
required-features = ["json"]

[[test]]
name = "json"
path = "tests/json/main.rs"
required-features = ["json"]
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,9 @@ Also check out the [documentation](/documentation.md).
- [x] GET configuration field
- [x] PUT configuration field
- [x] user defined types
- [ ] JSON support
- [x] JSON support
- [ ] custom validators
- [ ] on change callbacks
- [ ] defaults from env

## Thanks

Expand Down
6 changes: 6 additions & 0 deletions choices-derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,18 @@ categories = ["web-programming"]
edition = "2018"
license = "MIT"

[features]
default = []
json = ["serde", "serde_json"]

[dependencies]
syn = { version = "1", features = ["full"] }
quote = "1"
proc-macro2 = "1"
proc-macro-error = "1"
derive-new = "0.5"
serde = { version = "1.0", optional = true, features = ["derive"] }
serde_json = { version = "1.0", optional = true }

[lib]
proc-macro = true
16 changes: 14 additions & 2 deletions choices-derive/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use syn::{

/// All types of attribute available in choices.
pub(crate) enum ChoicesAttribute {
// single-identifier attributes
Json(Ident),
// ident = "string literal"
RootPath(Ident, LitStr),
}
Expand Down Expand Up @@ -55,7 +57,10 @@ impl Parse for ChoicesAttribute {
abort!(name, "unexpected attribute: {}", name_str);
} else {
// Attributes represented with a sole identifier.
abort!(name, "unexpected attribute: {}", name_str);
match name_str.as_ref() {
"json" => Ok(Json(name)),
_ => abort!(name, "unexpected attribute: {}", name_str),
}
}
}
}
Expand All @@ -73,18 +78,25 @@ fn parse_choices_attributes(attrs: &[Attribute]) -> Vec<ChoicesAttribute> {

pub(crate) struct Attributes {
pub(crate) root_path: Option<TokenStream>,
pub(crate) json: bool,
}

impl Attributes {
fn new() -> Self {
Self { root_path: None }
Self {
root_path: None,
json: false,
}
}

fn push_attrs(&mut self, attrs: &[Attribute]) {
use ChoicesAttribute::*;

for attr in parse_choices_attributes(attrs) {
match attr {
Json(_) => {
self.json = true;
}
RootPath(_, path) => {
self.root_path = Some(quote!(#path));
}
Expand Down
6 changes: 6 additions & 0 deletions choices-derive/src/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//! Collection of various constants.
pub(crate) const CONTENT_TYPE_HEADER: &str = "Content-Type";
pub(crate) const CONTENT_TYPE_TEXT: &str = "text/plain; charset=utf-8";
#[cfg(feature = "json")]
pub(crate) const CONTENT_TYPE_JSON: &str = "application/json";
52 changes: 50 additions & 2 deletions choices-derive/src/index.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,25 @@
use crate::util::compute_type_string;
use derive_new::new;
#[cfg(not(feature = "json"))]
use proc_macro_error::abort_call_site;
use syn::{punctuated::Punctuated, token::Comma, *};

#[derive(new)]
pub(crate) struct IndexData {
pub(crate) body: String,
pub(crate) content_type: &'static str,
}

/// Returns the body of the configuration index page.
pub(crate) fn compute_index_string(fields: &Punctuated<Field, Comma>) -> String {
pub(crate) fn compute_index(fields: &Punctuated<Field, Comma>, json: bool) -> IndexData {
if json {
compute_index_json(fields)
} else {
compute_index_text(fields)
}
}

fn compute_index_text(fields: &Punctuated<Field, Comma>) -> IndexData {
let mut index = "Available configuration options:\n".to_string();
fields.iter().for_each(|field| {
let field_ident = field
Expand All @@ -12,5 +29,36 @@ pub(crate) fn compute_index_string(fields: &Punctuated<Field, Comma>) -> String
let type_name = compute_type_string(&field.ty);
index += &format!(" - {}: {}\n", &field_ident.to_string(), type_name);
});
index
IndexData::new(index, crate::constants::CONTENT_TYPE_TEXT)
}

fn compute_index_json(_fields: &Punctuated<Field, Comma>) -> IndexData {
#[cfg(not(feature = "json"))]
abort_call_site!("you must enable the choices feature `json` in order to use it in a macro");

#[cfg(feature = "json")]
{
use serde::Serialize;

#[derive(Serialize, new)]
struct Entry {
name: String,
r#type: String,
}

let v: Vec<_> = _fields
.iter()
.map(|field| {
let field_ident = field
.ident
.as_ref()
.expect("unnamed fields are not supported!");
Entry::new(field_ident.to_string(), compute_type_string(&field.ty))
})
.collect();
IndexData::new(
serde_json::to_string(&v).expect("failed to serialize index json"),
crate::constants::CONTENT_TYPE_JSON,
)
}
}
1 change: 1 addition & 0 deletions choices-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
extern crate proc_macro;

mod attributes;
mod constants;
mod index;
mod util;
mod warp;
Expand Down
Loading

0 comments on commit f8f0842

Please sign in to comment.