├── .gitignore ├── .travis.yml ├── Cargo.toml ├── tests └── test_prefix.rs ├── LICENSE ├── readme.md ├── src └── lib.rs └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | 4 | notes.md 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | - nightly 5 | matrix: 6 | allow_failures: 7 | - rust: nightly 8 | fast_finish: true 9 | cache: cargo 10 | script: 11 | - cargo test --verbose 12 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "serde_prefix" 3 | version = "0.1.0" 4 | authors = ["Jonathan Sundqvist "] 5 | edition = "2018" 6 | description = "A macro for usage with serde to prefix all attributes in structs and enum" 7 | keywords = ["serde"] 8 | license = "MIT" 9 | homepage = "https://github.com/jonathan-s/serde-prefix" 10 | repository = "https://github.com/jonathan-s/serde-prefix" 11 | readme = "readme.md" 12 | 13 | [lib] 14 | proc-macro = true 15 | 16 | [dependencies] 17 | serde = { version = "^1", features = ["derive"] } 18 | serde_json = "^1" 19 | syn = { version = "^0.15", features = ["full"] } 20 | quote = "^0.6" 21 | -------------------------------------------------------------------------------- /tests/test_prefix.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate serde_prefix; 3 | extern crate serde; 4 | 5 | use serde::{Serialize, Deserialize}; 6 | 7 | 8 | #[prefix_all("test_")] 9 | #[derive(Serialize, Deserialize, Debug)] 10 | struct Point { 11 | x: i32, 12 | y: i32 13 | } 14 | 15 | #[prefix_all("test_")] 16 | #[derive(Serialize)] 17 | enum TestEnum { 18 | Hello, 19 | Point {x: i32, y: i32} 20 | } 21 | 22 | #[test] 23 | fn test_prefix_struct() { 24 | let point = Point { x: 1, y: 2 }; 25 | let serialized = serde_json::to_string(&point).unwrap(); 26 | let json = r#"{"test_x":1,"test_y":2}"#; 27 | assert_eq!(serialized, json); 28 | } 29 | 30 | #[test] 31 | fn test_enum() { 32 | let serialized = serde_json::to_string(&TestEnum::Point {x:1, y:1}).unwrap(); 33 | let json = r#"{"test_Point":{"x":1,"y":1}}"#; 34 | assert_eq!(serialized, json); 35 | 36 | let serialized = serde_json::to_string(&TestEnum::Hello).unwrap(); 37 | assert_eq!(serialized, "\"test_Hello\""); 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Jonathan Sundqvist 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | [![Build Status]][travis] [![Latest Version]][crates.io] 2 | 3 | [Build Status]: https://travis-ci.org/jonathan-s/serde-prefix.svg?branch=master 4 | [travis]: https://travis-ci.org/jonathan-s/serde-prefix 5 | 6 | [Latest Version]: https://img.shields.io/crates/v/serde_prefix.svg 7 | [crates.io]: https://crates.io/crates/serde_prefix 8 | 9 | # Serde Prefix 10 | 11 | A small extension to serde that will allow you to use the macro `#[prefix_all("myprefix_")`. The macro will prefix each attribute in a struct or enum with the prefix of your choice. 12 | 13 | Behind the doors it's using `#[serde(rename = "...")]` to rename each attribute with the prefix defined in prefix_all. 14 | 15 | ## Usage 16 | 17 | ```rust 18 | #[macro_use] 19 | extern crate serde_prefix; 20 | extern crate serde; 21 | 22 | use serde::{Serialize, Deserialize}; 23 | 24 | 25 | #[prefix_all("test_")] 26 | #[derive(Serialize, Debug)] 27 | struct Point { 28 | x: i32, 29 | y: i32 30 | } 31 | 32 | 33 | let point = Point { x: 1, y: 2 }; 34 | let serialized = serde_json::to_string(&point).unwrap(); 35 | let json = r#"{"test_x":1,"test_y":2}"#; 36 | assert_eq!(serialized, json); 37 | ``` 38 | 39 | If there is anything that you are missing create an issue :). 40 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate proc_macro; 2 | #[macro_use] 3 | extern crate syn; 4 | extern crate quote; 5 | 6 | use quote::ToTokens; 7 | use syn::{ 8 | AttributeArgs, 9 | Item, 10 | ItemStruct, 11 | ItemEnum, 12 | Attribute, 13 | parse_quote 14 | }; 15 | use proc_macro::{TokenStream}; 16 | 17 | 18 | fn create_attribute(prefix: &str, field_name: &str) -> Attribute { 19 | let attr_prefix = format!("{}{}", prefix, field_name); 20 | let attr: Attribute = parse_quote! { #[serde(rename = #attr_prefix)] }; 21 | attr 22 | } 23 | 24 | fn handle_enum(token: &mut ItemEnum, prefix: &str) -> TokenStream { 25 | 26 | let variants = &mut token.variants; 27 | for variant in variants.iter_mut() { 28 | let field_name = variant.ident.to_string(); 29 | let attr = create_attribute(prefix, &field_name[..]); 30 | variant.attrs = vec![attr]; 31 | } 32 | 33 | TokenStream::from(token.into_token_stream()) 34 | } 35 | 36 | 37 | fn handle_struct(token: &mut ItemStruct, prefix: &str) -> TokenStream { 38 | 39 | let fields = &mut token.fields; 40 | for field in fields.iter_mut() { 41 | let field_name = field.ident.as_ref().unwrap().to_string(); 42 | let attr = create_attribute(prefix, &field_name[..]); 43 | field.attrs = vec![attr]; 44 | } 45 | 46 | TokenStream::from(token.into_token_stream()) 47 | } 48 | 49 | 50 | #[proc_macro_attribute] 51 | pub fn prefix_all(attr: TokenStream, item: TokenStream) -> TokenStream { 52 | 53 | let attr_args: Vec<_> = parse_macro_input!(attr as AttributeArgs); 54 | if attr_args.len() != 1 { 55 | panic!("prefix_all needs one attribute; the prefix"); 56 | } 57 | let prefix = Some(&attr_args[0]); 58 | let prefix = prefix.map(|meta| match meta { 59 | syn::NestedMeta::Literal(lit) => lit, 60 | _ => panic!("The attribute is not a string") 61 | }) 62 | .map(|lit| match lit { 63 | syn::Lit::Str(string) => string, 64 | _ => panic!("The attribute is not a string") 65 | }) 66 | .unwrap().value(); 67 | 68 | 69 | let mut input = parse_macro_input!(item as Item); 70 | let tokenstream = match input { 71 | Item::Enum(ref mut item_enum) => handle_enum(item_enum, &prefix[..]), 72 | Item::Struct(ref mut item_struct) => handle_struct(item_struct, &prefix[..]), 73 | _ => panic!("You can't use the macro on this type") 74 | }; 75 | 76 | tokenstream 77 | } 78 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "itoa" 5 | version = "0.4.4" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | 8 | [[package]] 9 | name = "proc-macro2" 10 | version = "0.4.30" 11 | source = "registry+https://github.com/rust-lang/crates.io-index" 12 | dependencies = [ 13 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 14 | ] 15 | 16 | [[package]] 17 | name = "quote" 18 | version = "0.6.12" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | dependencies = [ 21 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 22 | ] 23 | 24 | [[package]] 25 | name = "ryu" 26 | version = "0.2.8" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | 29 | [[package]] 30 | name = "serde" 31 | version = "1.0.92" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | dependencies = [ 34 | "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", 35 | ] 36 | 37 | [[package]] 38 | name = "serde_derive" 39 | version = "1.0.92" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | dependencies = [ 42 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 43 | "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", 44 | "syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", 45 | ] 46 | 47 | [[package]] 48 | name = "serde_json" 49 | version = "1.0.39" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | dependencies = [ 52 | "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 53 | "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 54 | "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", 55 | ] 56 | 57 | [[package]] 58 | name = "serde_prefix" 59 | version = "0.1.0" 60 | dependencies = [ 61 | "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", 62 | "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", 63 | "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", 64 | "syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", 65 | ] 66 | 67 | [[package]] 68 | name = "syn" 69 | version = "0.15.36" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | dependencies = [ 72 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 73 | "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", 74 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 75 | ] 76 | 77 | [[package]] 78 | name = "unicode-xid" 79 | version = "0.1.0" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | 82 | [metadata] 83 | "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" 84 | "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" 85 | "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" 86 | "checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f" 87 | "checksum serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "32746bf0f26eab52f06af0d0aa1984f641341d06d8d673c693871da2d188c9be" 88 | "checksum serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "46a3223d0c9ba936b61c0d2e3e559e3217dbfb8d65d06d26e8b3c25de38bae3e" 89 | "checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" 90 | "checksum syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)" = "8b4f551a91e2e3848aeef8751d0d4eec9489b6474c720fd4c55958d8d31a430c" 91 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 92 | --------------------------------------------------------------------------------