├── .gitignore ├── dyn-clonable ├── .gitignore ├── src │ └── lib.rs ├── Cargo.toml └── examples │ └── simple.rs ├── Cargo.toml ├── dyn-clonable-impl ├── .gitignore ├── Cargo.toml └── src │ └── lib.rs ├── README.md ├── .rustfmt.toml └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /dyn-clonable/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["dyn-clonable", "dyn-clonable-impl"] -------------------------------------------------------------------------------- /dyn-clonable-impl/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /dyn-clonable/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[doc(hidden)] 2 | pub use dyn_clone; 3 | 4 | // Re-export the attribute macro. 5 | pub use dyn_clonable_impl::*; 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dyn-clonable 2 | 3 | Provides a proc_macro attribute wrapper for [dyn-clone](https://docs.rs/dyn-clone/*/dyn_clone/). 4 | 5 | # Usage 6 | 7 | ```rust 8 | use dyn_clonable::*; 9 | 10 | #[clonable] 11 | trait MyTrait: Clone { 12 | fn recite(&self); 13 | } 14 | ``` 15 | 16 | For additional information, see [dtolnay's](https://github.com/dtolnay) [dyn-clone](https://docs.rs/dyn-clone/*/dyn_clone/). 17 | 18 | License: MIT 19 | -------------------------------------------------------------------------------- /dyn-clonable/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Jacob Brown "] 3 | edition = "2018" 4 | name = "dyn-clonable" 5 | version = "0.9.2" 6 | description = "Attribute wrapper for dyn-clone" 7 | license = "MIT" 8 | repository = "https://github.com/kardeiz/objekt-clonable" 9 | readme = "../README.md" 10 | 11 | [dependencies] 12 | dyn-clone = "1.0" 13 | 14 | [dependencies.dyn-clonable-impl] 15 | path = "../dyn-clonable-impl" 16 | version = "0.9" 17 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | unstable_features = true 2 | use_small_heuristics = "Max" 3 | brace_style = "PreferSameLine" 4 | fn_single_line = true 5 | reorder_impl_items = true 6 | trailing_comma = "Never" 7 | use_field_init_shorthand = true 8 | use_try_shorthand = true 9 | fn_args_density = "Tall" 10 | condense_wildcard_suffixes = true 11 | where_single_line = true 12 | format_strings = true 13 | imports_indent = "Block" 14 | merge_imports = true 15 | struct_lit_single_line = true 16 | max_width = 100 -------------------------------------------------------------------------------- /dyn-clonable-impl/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Jacob Brown "] 3 | edition = "2018" 4 | name = "dyn-clonable-impl" 5 | version = "0.9.2" 6 | description = "Attribute wrapper for dyn-clone" 7 | license = "MIT" 8 | repository = "https://github.com/kardeiz/objekt-clonable" 9 | readme = "../README.md" 10 | 11 | [dependencies] 12 | proc-macro2 = "1.0" 13 | quote = "1.0" 14 | 15 | [dependencies.syn] 16 | features = ["full"] 17 | version = "2.0" 18 | 19 | [dev-dependencies] 20 | dyn-clone = "1.0" 21 | 22 | [lib] 23 | proc-macro = true 24 | -------------------------------------------------------------------------------- /dyn-clonable/examples/simple.rs: -------------------------------------------------------------------------------- 1 | use dyn_clonable::*; 2 | 3 | use std::io::Read; 4 | 5 | #[clonable] 6 | trait Difficult: Clone 7 | where R: Read { 8 | /* ... */ 9 | } 10 | 11 | #[clonable] 12 | trait MyTrait: Clone { 13 | fn recite(&self); 14 | } 15 | 16 | #[clonable] 17 | trait MyTrait2: std::clone::Clone { 18 | fn recite2(&self); 19 | } 20 | 21 | impl MyTrait for String { 22 | fn recite(&self) { 23 | println!("{} ♫", self); 24 | } 25 | } 26 | 27 | #[derive(Clone)] 28 | struct Container { 29 | trait_object: Box 30 | } 31 | 32 | fn main() { 33 | let line = "The slithy structs did gyre and gimble the namespace"; 34 | 35 | // Build a trait object holding a String. 36 | // This requires String to implement MyTrait and std::clone::Clone. 37 | let x: Box = Box::new(String::from(line)); 38 | 39 | x.recite(); 40 | 41 | // The type of x2 is a Box cloned from x. 42 | let x2 = dyn_clone::clone_box(&*x); 43 | 44 | x2.recite(); 45 | } 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2022 Jacob Brown 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 | 23 | -------------------------------------------------------------------------------- /dyn-clonable-impl/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate proc_macro; 2 | 3 | use proc_macro::TokenStream; 4 | use quote::quote; 5 | 6 | use syn::*; 7 | 8 | #[proc_macro_attribute] 9 | pub fn clonable(_attrs: TokenStream, item: TokenStream) -> TokenStream { 10 | let mut item_trait = parse_macro_input!(item as ItemTrait); 11 | 12 | let item_trait_ident = &item_trait.ident; 13 | 14 | let cloneish_paths = &[quote!(Clone), quote!(std::clone::Clone), quote!(::std::clone::Clone)]; 15 | 16 | if let Some(path) = item_trait 17 | .supertraits 18 | .iter_mut() 19 | .filter_map(|x| match x { 20 | TypeParamBound::Trait(y) => Some(y), 21 | _ => None 22 | }) 23 | .map(|x| &mut x.path) 24 | .find(|x| { 25 | let s = quote!(#x).to_string(); 26 | cloneish_paths.iter().any(|y| y.to_string() == s) 27 | }) 28 | { 29 | *path = parse_quote!(dyn_clonable::dyn_clone::DynClone); 30 | } else { 31 | panic!("`Clone` must be present in trait supertrait list"); 32 | } 33 | 34 | let (impl_generics, ty_generics, where_clause) = item_trait.generics.split_for_impl(); 35 | 36 | (quote! { 37 | #item_trait 38 | dyn_clonable::dyn_clone::clone_trait_object!(#impl_generics #item_trait_ident #ty_generics #where_clause); 39 | }) 40 | .into() 41 | } 42 | --------------------------------------------------------------------------------