changeset 65:f52e84dfb3fa

Fix #9: carry all dependencies automatically.
author Lewin Bormann <lbo@spheniscida.de>
date Fri, 24 Dec 2021 13:37:11 +0100
parents 8a7d29f97802
children aefbc4424cb6
files Cargo.toml inner/Cargo.toml inner/src/lib.rs src/lib.rs
diffstat 4 files changed, 375 insertions(+), 349 deletions(-) [+]
line wrap: on
line diff
--- a/Cargo.toml	Tue Nov 23 14:06:53 2021 +0100
+++ b/Cargo.toml	Fri Dec 24 13:37:11 2021 +0100
@@ -1,27 +1,24 @@
 [package]
 name = "memoize"
-version = "0.1.9"
-description = "Attribute macro for auto-memoizing functions with somewhat-simple signatures"
-keywords = ["memoization", "cache", "proc-macro"]
-authors = ["Lewin Bormann <lewin@lewin-bormann.info>"]
-homepage = "https://github.com/dermesser/memoize"
-repository = "https://github.com/dermesser/memoize"
-documentation = "https://docs.rs/memoize"
-edition = "2018"
+version = "0.2.0"
+description = "Attribute macro for auto-memoizing functions with somewhat-simple signatures"    
+keywords = ["memoization", "cache", "proc-macro"]    
+authors = ["Lewin Bormann <lewin@lewin-bormann.info>"]    
+homepage = "https://github.com/dermesser/memoize"    
+repository = "https://github.com/dermesser/memoize"    
+documentation = "https://docs.rs/memoize"    
+edition = "2018"    
 license = "MIT"
 
-[lib]
-proc-macro = true
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+[dependencies]
 
-[dependencies]
+memoize-inner = { path = "inner/", version = "0.2.0" }
 lazy_static = "1.4"
-proc-macro2 = "1.0"
-quote = "1.0"
-syn = { version = "1.0", features = ["full"] }
+lru = { version = "0.6", optional = true }
 
-lru = { version = "0.6", optional = true }
+[workspace]
+members = ["inner/"]
 
 [features]
 default = []
-full = ["lru"]
+full = ["lru", "memoize-inner/full"]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inner/Cargo.toml	Fri Dec 24 13:37:11 2021 +0100
@@ -0,0 +1,24 @@
+[package]
+name = "memoize-inner"
+version = "0.2.0"
+description = "Helper crate for memoize."
+authors = ["Lewin Bormann <lewin@lewin-bormann.info>"]
+homepage = "https://github.com/dermesser/memoize"
+repository = "https://github.com/dermesser/memoize"
+documentation = "https://docs.rs/memoize-inner"
+edition = "2018"
+license = "MIT"
+
+[lib]
+proc-macro = true
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+lazy_static = "1.4"
+proc-macro2 = "1.0"
+quote = "1.0"
+syn = { version = "1.0", features = ["full"] }
+
+[features]
+default = []
+full = []
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inner/src/lib.rs	Fri Dec 24 13:37:11 2021 +0100
@@ -0,0 +1,333 @@
+#![crate_type = "proc-macro"]
+#![allow(unused_imports)] // Spurious complaints about a required trait import.
+
+use syn::{self, parse_macro_input, spanned::Spanned, ItemFn};
+
+use proc_macro::TokenStream;
+use quote::{self, ToTokens};
+
+// This implementation of the storage backend does not depend on any more crates.
+#[cfg(not(feature = "full"))]
+mod store {
+    use proc_macro::TokenStream;
+
+    /// Returns tokenstreams (for quoting) of the store type and an expression to initialize it.
+    pub fn construct_cache(
+        attr: &TokenStream,
+        key_type: proc_macro2::TokenStream,
+        value_type: proc_macro2::TokenStream,
+    ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
+        if !attr.is_empty() {
+            return (
+                syn::Error::new_spanned(proc_macro2::TokenStream::from(attr.clone()),
+                    "memoize error: Attributes are specified, but the feature 'full' is not enabled! To fix this, compile with `--features=full`.",
+                )
+                .to_compile_error(),
+                proc_macro2::TokenStream::new(),
+            );
+        }
+        // This is the unbounded default.
+        (
+            quote::quote! { std::collections::HashMap<#key_type, #value_type> },
+            quote::quote! { std::collections::HashMap::new() },
+        )
+    }
+
+    /// Returns names of methods as TokenStreams to insert and get (respectively) elements from a
+    /// store.
+    pub fn cache_access_methods(
+        _attr: &TokenStream,
+    ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
+        (quote::quote! { insert }, quote::quote! { get })
+    }
+}
+
+// This implementation of the storage backend also depends on the `lru` crate.
+#[cfg(feature = "full")]
+mod store {
+    use proc_macro::TokenStream;
+    use syn::{parse as p, Expr};
+
+    #[derive(Default, Clone)]
+    pub(crate) struct CacheOptions {
+        lru_max_entries: Option<usize>,
+        pub(crate) time_to_live: Option<Expr>,
+    }
+
+    #[derive(Clone)]
+    enum CacheOption {
+        LRUMaxEntries(usize),
+        TimeToLive(Expr),
+    }
+
+    syn::custom_keyword!(Capacity);
+    syn::custom_keyword!(TimeToLive);
+    syn::custom_punctuation!(Colon, :);
+
+    // To extend option parsing, add functionality here.
+    impl p::Parse for CacheOption {
+        fn parse(input: p::ParseStream) -> syn::Result<Self> {
+            let la = input.lookahead1();
+            if la.peek(Capacity) {
+                let _: Capacity = input.parse().unwrap();
+                let _: Colon = input.parse().unwrap();
+                let cap: syn::LitInt = input.parse().unwrap();
+
+                return Ok(CacheOption::LRUMaxEntries(cap.base10_parse()?));
+            }
+            if la.peek(TimeToLive) {
+                let _: TimeToLive = input.parse().unwrap();
+                let _: Colon = input.parse().unwrap();
+                let cap: syn::Expr = input.parse().unwrap();
+
+                return Ok(CacheOption::TimeToLive(cap));
+            }
+            Err(la.error())
+        }
+    }
+
+    impl p::Parse for CacheOptions {
+        fn parse(input: p::ParseStream) -> syn::Result<Self> {
+            let f: syn::punctuated::Punctuated<CacheOption, syn::Token![,]> =
+                input.parse_terminated(CacheOption::parse)?;
+            let mut opts = Self::default();
+
+            for opt in f {
+                match opt {
+                    CacheOption::LRUMaxEntries(cap) => opts.lru_max_entries = Some(cap),
+                    CacheOption::TimeToLive(sec) => opts.time_to_live = Some(sec),
+                }
+            }
+            Ok(opts)
+        }
+    }
+
+    /// Returns TokenStreams to be used in quote!{} for parametrizing the memoize store variable,
+    /// and initializing it.
+    ///
+    /// First return value: Type of store ("Container<K,V>").
+    /// Second return value: Initializer syntax ("Container::<K,V>::new()").
+    pub fn construct_cache(
+        attr: &TokenStream,
+        key_type: proc_macro2::TokenStream,
+        value_type: proc_macro2::TokenStream,
+    ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
+        let options: CacheOptions = syn::parse(attr.clone()).unwrap();
+
+        let value_type = match options.time_to_live {
+            None => quote::quote! {#value_type},
+            Some(_) => quote::quote! {(std::time::Instant, #value_type)},
+        };
+        // This is the unbounded default.
+        match options.lru_max_entries {
+            None => (
+                quote::quote! { std::collections::HashMap<#key_type, #value_type> },
+                quote::quote! { std::collections::HashMap::new() },
+            ),
+            Some(cap) => (
+                quote::quote! { ::memoize::lru::LruCache<#key_type, #value_type> },
+                quote::quote! { ::memoize::lru::LruCache::new(#cap) },
+            ),
+        }
+    }
+
+    /// Returns names of methods as TokenStreams to insert and get (respectively) elements from a
+    /// store.
+    pub fn cache_access_methods(
+        attr: &TokenStream,
+    ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
+        let options: CacheOptions = syn::parse(attr.clone()).unwrap();
+
+        // This is the unbounded default.
+        match options.lru_max_entries {
+            None => (quote::quote! { insert }, quote::quote! { get }),
+            Some(_) => (quote::quote! { put }, quote::quote! { get }),
+        }
+    }
+}
+
+/**
+ * memoize is an attribute to create a memoized version of a (simple enough) function.
+ *
+ * So far, it works on functions with one or more arguments which are `Clone`- and `Hash`-able,
+ * returning a `Clone`-able value. Several clones happen within the storage and recall layer, with
+ * the assumption being that `memoize` is used to cache such expensive functions that very few
+ * `clone()`s do not matter. `memoize` doesn't work on methods (functions with `[&/&mut/]self`
+ * receiver).
+ *
+ * Calls are memoized for the lifetime of a program, using a statically allocated, Mutex-protected
+ * HashMap.
+ *
+ * Memoizing functions is very simple: As long as the above-stated requirements are fulfilled,
+ * simply use the `#[memoize::memoize]` attribute:
+ *
+ * ```
+ * use memoize::memoize;
+ * #[memoize]
+ * fn hello(arg: String, arg2: usize) -> bool {
+ *      arg.len()%2 == arg2
+ * }
+ *
+ * // `hello` is only called once.
+ * assert!(! hello("World".to_string(), 0));
+ * assert!(! hello("World".to_string(), 0));
+ * ```
+ *
+ * If you need to use the un-memoized function, it is always available as `memoized_original_{fn}`,
+ * in this case: `memoized_original_hello()`.
+ *
+ * See the `examples` for concrete applications.
+ *
+ * *The following descriptions need the `full` feature enabled.*
+ *
+ * The `memoize` attribute can take further parameters in order to use an LRU cache:
+ * `#[memoize(Capacity: 1234)]`. In that case, instead of a `HashMap` we use an `lru::LruCache`
+ * with the given capacity.
+ * `#[memoize(TimeToLive: Duration::from_secs(2))]`. In that case, cached value will be actual
+ * no longer than duration provided and refreshed with next request. If you prefer chrono::Duration,
+ * it can be also used: `#[memoize(TimeToLive: chrono::Duration::hours(9).to_std().unwrap()]`
+ *
+ * This mechanism can, in principle, be extended (in the source code) to any other cache mechanism.
+ *
+ */
+#[proc_macro_attribute]
+pub fn memoize(attr: TokenStream, item: TokenStream) -> TokenStream {
+    let func = parse_macro_input!(item as ItemFn);
+    let sig = &func.sig;
+
+    let fn_name = &sig.ident.to_string();
+    let renamed_name = format!("memoized_original_{}", fn_name);
+    let map_name = format!("memoized_mapping_{}", fn_name);
+
+    // Extracted from the function signature.
+    let input_types: Vec<Box<syn::Type>>;
+    let input_names: Vec<Box<syn::Pat>>;
+    let return_type;
+
+    match check_signature(sig) {
+        Ok((t, n)) => {
+            input_types = t;
+            input_names = n;
+        }
+        Err(e) => return e.to_compile_error().into(),
+    }
+
+    let input_tuple_type = quote::quote! { (#(#input_types),*) };
+
+    match &sig.output {
+        syn::ReturnType::Default => return_type = quote::quote! { () },
+        syn::ReturnType::Type(_, ty) => return_type = ty.to_token_stream(),
+    }
+
+    // Construct storage for the memoized keys and return values.
+    let store_ident = syn::Ident::new(&map_name.to_uppercase(), sig.span());
+    let (cache_type, cache_init) = store::construct_cache(&attr, input_tuple_type, return_type);
+    let store = quote::quote! {
+        ::memoize::lazy_static::lazy_static! {
+            static ref #store_ident : std::sync::Mutex<#cache_type> =
+                std::sync::Mutex::new(#cache_init);
+        }
+    };
+
+    // Rename original function.
+    let mut renamed_fn = func.clone();
+    renamed_fn.sig.ident = syn::Ident::new(&renamed_name, func.sig.span());
+    let memoized_id = &renamed_fn.sig.ident;
+
+    // Construct memoizer function, which calls the original function.
+    let syntax_names_tuple = quote::quote! { (#(#input_names),*) };
+    let syntax_names_tuple_cloned = quote::quote! { (#(#input_names.clone()),*) };
+    let (insert_fn, get_fn) = store::cache_access_methods(&attr);
+    #[cfg(feature = "full")]
+    let memoizer = {
+        let options: store::CacheOptions = syn::parse(attr.clone().into()).unwrap();
+        match options.time_to_live {
+            None => quote::quote! {
+                #sig {
+                    {
+                        let mut hm = &mut #store_ident.lock().unwrap();
+                        if let Some(r) = hm.#get_fn(&#syntax_names_tuple_cloned) {
+                            return r.clone();
+                        }
+                    }
+                    let r = #memoized_id(#(#input_names.clone()),*);
+                    let mut hm = &mut #store_ident.lock().unwrap();
+                    hm.#insert_fn(#syntax_names_tuple, r.clone());
+                    r
+                }
+            },
+            Some(ttl) => quote::quote! {
+                #sig {
+                    {
+                        let mut hm = &mut #store_ident.lock().unwrap();
+                        if let Some((last_updated, r)) = hm.#get_fn(&#syntax_names_tuple_cloned) {
+                            if last_updated.elapsed() < #ttl {
+                                return r.clone();
+                            }
+                        }
+                    }
+                    let r = #memoized_id(#(#input_names.clone()),*);
+                    let mut hm = &mut #store_ident.lock().unwrap();
+                    hm.#insert_fn(#syntax_names_tuple, (std::time::Instant::now(), r.clone()));
+                    r
+                }
+            },
+        }
+    };
+    #[cfg(not(feature = "full"))]
+    let memoizer = quote::quote! {
+        #sig {
+            {
+                let mut hm = &mut #store_ident.lock().unwrap();
+                if let Some(r) = hm.#get_fn(&#syntax_names_tuple_cloned) {
+                    return r.clone();
+                }
+            }
+            let r = #memoized_id(#(#input_names.clone()),*);
+            let mut hm = &mut #store_ident.lock().unwrap();
+            hm.#insert_fn(#syntax_names_tuple, r.clone());
+            r
+        }
+    };
+
+    (quote::quote! {
+        #store
+
+        #renamed_fn
+
+        #memoizer
+    })
+    .into()
+}
+
+fn check_signature(
+    sig: &syn::Signature,
+) -> Result<(Vec<Box<syn::Type>>, Vec<Box<syn::Pat>>), syn::Error> {
+    if let syn::FnArg::Receiver(_) = sig.inputs[0] {
+        return Err(syn::Error::new(
+            sig.span(),
+            "Cannot memoize method (self-receiver) without arguments!",
+        ));
+    }
+
+    let mut types = vec![];
+    let mut names = vec![];
+    for a in &sig.inputs {
+        if let syn::FnArg::Typed(ref arg) = a {
+            types.push(arg.ty.clone());
+
+            if let syn::Pat::Ident(_) = &*arg.pat {
+                names.push(arg.pat.clone());
+            } else {
+                return Err(syn::Error::new(
+                    sig.span(),
+                    "Cannot memoize arbitrary patterns!",
+                ));
+            }
+        }
+    }
+    Ok((types, names))
+}
+
+#[cfg(test)]
+mod tests {}
--- a/src/lib.rs	Tue Nov 23 14:06:53 2021 +0100
+++ b/src/lib.rs	Fri Dec 24 13:37:11 2021 +0100
@@ -1,333 +1,5 @@
-#![crate_type = "proc-macro"]
-#![allow(unused_imports)] // Spurious complaints about a required trait import.
-
-use syn::{self, parse_macro_input, spanned::Spanned, ItemFn};
-
-use proc_macro::TokenStream;
-use quote::{self, ToTokens};
-
-// This implementation of the storage backend does not depend on any more crates.
-#[cfg(not(feature = "full"))]
-mod store {
-    use proc_macro::TokenStream;
-
-    /// Returns tokenstreams (for quoting) of the store type and an expression to initialize it.
-    pub fn construct_cache(
-        attr: &TokenStream,
-        key_type: proc_macro2::TokenStream,
-        value_type: proc_macro2::TokenStream,
-    ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
-        if !attr.is_empty() {
-            return (
-                syn::Error::new_spanned(proc_macro2::TokenStream::from(attr.clone()),
-                    "memoize error: Attributes are specified, but the feature 'full' is not enabled! To fix this, compile with `--features=full`.",
-                )
-                .to_compile_error(),
-                proc_macro2::TokenStream::new(),
-            );
-        }
-        // This is the unbounded default.
-        (
-            quote::quote! { std::collections::HashMap<#key_type, #value_type> },
-            quote::quote! { std::collections::HashMap::new() },
-        )
-    }
-
-    /// Returns names of methods as TokenStreams to insert and get (respectively) elements from a
-    /// store.
-    pub fn cache_access_methods(
-        _attr: &TokenStream,
-    ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
-        (quote::quote! { insert }, quote::quote! { get })
-    }
-}
-
-// This implementation of the storage backend also depends on the `lru` crate.
-#[cfg(feature = "full")]
-mod store {
-    use proc_macro::TokenStream;
-    use syn::{parse as p, Expr};
-
-    #[derive(Default, Clone)]
-    pub(crate) struct CacheOptions {
-        lru_max_entries: Option<usize>,
-        pub(crate) time_to_live: Option<Expr>,
-    }
-
-    #[derive(Clone)]
-    enum CacheOption {
-        LRUMaxEntries(usize),
-        TimeToLive(Expr),
-    }
-
-    syn::custom_keyword!(Capacity);
-    syn::custom_keyword!(TimeToLive);
-    syn::custom_punctuation!(Colon, :);
-
-    // To extend option parsing, add functionality here.
-    impl p::Parse for CacheOption {
-        fn parse(input: p::ParseStream) -> syn::Result<Self> {
-            let la = input.lookahead1();
-            if la.peek(Capacity) {
-                let _: Capacity = input.parse().unwrap();
-                let _: Colon = input.parse().unwrap();
-                let cap: syn::LitInt = input.parse().unwrap();
-
-                return Ok(CacheOption::LRUMaxEntries(cap.base10_parse()?));
-            }
-            if la.peek(TimeToLive) {
-                let _: TimeToLive = input.parse().unwrap();
-                let _: Colon = input.parse().unwrap();
-                let cap: syn::Expr = input.parse().unwrap();
-
-                return Ok(CacheOption::TimeToLive(cap));
-            }
-            Err(la.error())
-        }
-    }
-
-    impl p::Parse for CacheOptions {
-        fn parse(input: p::ParseStream) -> syn::Result<Self> {
-            let f: syn::punctuated::Punctuated<CacheOption, syn::Token![,]> =
-                input.parse_terminated(CacheOption::parse)?;
-            let mut opts = Self::default();
-
-            for opt in f {
-                match opt {
-                    CacheOption::LRUMaxEntries(cap) => opts.lru_max_entries = Some(cap),
-                    CacheOption::TimeToLive(sec) => opts.time_to_live = Some(sec),
-                }
-            }
-            Ok(opts)
-        }
-    }
-
-    /// Returns TokenStreams to be used in quote!{} for parametrizing the memoize store variable,
-    /// and initializing it.
-    ///
-    /// First return value: Type of store ("Container<K,V>").
-    /// Second return value: Initializer syntax ("Container::<K,V>::new()").
-    pub fn construct_cache(
-        attr: &TokenStream,
-        key_type: proc_macro2::TokenStream,
-        value_type: proc_macro2::TokenStream,
-    ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
-        let options: CacheOptions = syn::parse(attr.clone()).unwrap();
-
-        let value_type = match options.time_to_live {
-            None => quote::quote! {#value_type},
-            Some(_) => quote::quote! {(std::time::Instant, #value_type)},
-        };
-        // This is the unbounded default.
-        match options.lru_max_entries {
-            None => (
-                quote::quote! { std::collections::HashMap<#key_type, #value_type> },
-                quote::quote! { std::collections::HashMap::new() },
-            ),
-            Some(cap) => (
-                quote::quote! { lru::LruCache<#key_type, #value_type> },
-                quote::quote! { lru::LruCache::new(#cap) },
-            ),
-        }
-    }
-
-    /// Returns names of methods as TokenStreams to insert and get (respectively) elements from a
-    /// store.
-    pub fn cache_access_methods(
-        attr: &TokenStream,
-    ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
-        let options: CacheOptions = syn::parse(attr.clone()).unwrap();
-
-        // This is the unbounded default.
-        match options.lru_max_entries {
-            None => (quote::quote! { insert }, quote::quote! { get }),
-            Some(_) => (quote::quote! { put }, quote::quote! { get }),
-        }
-    }
-}
+pub use ::memoize_inner::memoize;
+pub use ::lazy_static;
 
-/**
- * memoize is an attribute to create a memoized version of a (simple enough) function.
- *
- * So far, it works on functions with one or more arguments which are `Clone`- and `Hash`-able,
- * returning a `Clone`-able value. Several clones happen within the storage and recall layer, with
- * the assumption being that `memoize` is used to cache such expensive functions that very few
- * `clone()`s do not matter. `memoize` doesn't work on methods (functions with `[&/&mut/]self`
- * receiver).
- *
- * Calls are memoized for the lifetime of a program, using a statically allocated, Mutex-protected
- * HashMap.
- *
- * Memoizing functions is very simple: As long as the above-stated requirements are fulfilled,
- * simply use the `#[memoize::memoize]` attribute:
- *
- * ```
- * use memoize::memoize;
- * #[memoize]
- * fn hello(arg: String, arg2: usize) -> bool {
- *      arg.len()%2 == arg2
- * }
- *
- * // `hello` is only called once.
- * assert!(! hello("World".to_string(), 0));
- * assert!(! hello("World".to_string(), 0));
- * ```
- *
- * If you need to use the un-memoized function, it is always available as `memoized_original_{fn}`,
- * in this case: `memoized_original_hello()`.
- *
- * See the `examples` for concrete applications.
- *
- * *The following descriptions need the `full` feature enabled.*
- *
- * The `memoize` attribute can take further parameters in order to use an LRU cache:
- * `#[memoize(Capacity: 1234)]`. In that case, instead of a `HashMap` we use an `lru::LruCache`
- * with the given capacity.
- * `#[memoize(TimeToLive: Duration::from_secs(2))]`. In that case, cached value will be actual
- * no longer than duration provided and refreshed with next request. If you prefer chrono::Duration,
- * it can be also used: `#[memoize(TimeToLive: chrono::Duration::hours(9).to_std().unwrap()]`
- *
- * This mechanism can, in principle, be extended (in the source code) to any other cache mechanism.
- *
- */
-#[proc_macro_attribute]
-pub fn memoize(attr: TokenStream, item: TokenStream) -> TokenStream {
-    let func = parse_macro_input!(item as ItemFn);
-    let sig = &func.sig;
-
-    let fn_name = &sig.ident.to_string();
-    let renamed_name = format!("memoized_original_{}", fn_name);
-    let map_name = format!("memoized_mapping_{}", fn_name);
-
-    // Extracted from the function signature.
-    let input_types: Vec<Box<syn::Type>>;
-    let input_names: Vec<Box<syn::Pat>>;
-    let return_type;
-
-    match check_signature(sig) {
-        Ok((t, n)) => {
-            input_types = t;
-            input_names = n;
-        }
-        Err(e) => return e.to_compile_error().into(),
-    }
-
-    let input_tuple_type = quote::quote! { (#(#input_types),*) };
-
-    match &sig.output {
-        syn::ReturnType::Default => return_type = quote::quote! { () },
-        syn::ReturnType::Type(_, ty) => return_type = ty.to_token_stream(),
-    }
-
-    // Construct storage for the memoized keys and return values.
-    let store_ident = syn::Ident::new(&map_name.to_uppercase(), sig.span());
-    let (cache_type, cache_init) = store::construct_cache(&attr, input_tuple_type, return_type);
-    let store = quote::quote! {
-        lazy_static::lazy_static! {
-            static ref #store_ident : std::sync::Mutex<#cache_type> =
-                std::sync::Mutex::new(#cache_init);
-        }
-    };
-
-    // Rename original function.
-    let mut renamed_fn = func.clone();
-    renamed_fn.sig.ident = syn::Ident::new(&renamed_name, func.sig.span());
-    let memoized_id = &renamed_fn.sig.ident;
-
-    // Construct memoizer function, which calls the original function.
-    let syntax_names_tuple = quote::quote! { (#(#input_names),*) };
-    let syntax_names_tuple_cloned = quote::quote! { (#(#input_names.clone()),*) };
-    let (insert_fn, get_fn) = store::cache_access_methods(&attr);
-    #[cfg(feature = "full")]
-    let memoizer = {
-        let options: store::CacheOptions = syn::parse(attr.clone().into()).unwrap();
-        match options.time_to_live {
-            None => quote::quote! {
-                #sig {
-                    {
-                        let mut hm = &mut #store_ident.lock().unwrap();
-                        if let Some(r) = hm.#get_fn(&#syntax_names_tuple_cloned) {
-                            return r.clone();
-                        }
-                    }
-                    let r = #memoized_id(#(#input_names.clone()),*);
-                    let mut hm = &mut #store_ident.lock().unwrap();
-                    hm.#insert_fn(#syntax_names_tuple, r.clone());
-                    r
-                }
-            },
-            Some(ttl) => quote::quote! {
-                #sig {
-                    {
-                        let mut hm = &mut #store_ident.lock().unwrap();
-                        if let Some((last_updated, r)) = hm.#get_fn(&#syntax_names_tuple_cloned) {
-                            if last_updated.elapsed() < #ttl {
-                                return r.clone();
-                            }
-                        }
-                    }
-                    let r = #memoized_id(#(#input_names.clone()),*);
-                    let mut hm = &mut #store_ident.lock().unwrap();
-                    hm.#insert_fn(#syntax_names_tuple, (std::time::Instant::now(), r.clone()));
-                    r
-                }
-            },
-        }
-    };
-    #[cfg(not(feature = "full"))]
-    let memoizer = quote::quote! {
-        #sig {
-            {
-                let mut hm = &mut #store_ident.lock().unwrap();
-                if let Some(r) = hm.#get_fn(&#syntax_names_tuple_cloned) {
-                    return r.clone();
-                }
-            }
-            let r = #memoized_id(#(#input_names.clone()),*);
-            let mut hm = &mut #store_ident.lock().unwrap();
-            hm.#insert_fn(#syntax_names_tuple, r.clone());
-            r
-        }
-    };
-
-    (quote::quote! {
-        #store
-
-        #renamed_fn
-
-        #memoizer
-    })
-    .into()
-}
-
-fn check_signature(
-    sig: &syn::Signature,
-) -> Result<(Vec<Box<syn::Type>>, Vec<Box<syn::Pat>>), syn::Error> {
-    if let syn::FnArg::Receiver(_) = sig.inputs[0] {
-        return Err(syn::Error::new(
-            sig.span(),
-            "Cannot memoize method (self-receiver) without arguments!",
-        ));
-    }
-
-    let mut types = vec![];
-    let mut names = vec![];
-    for a in &sig.inputs {
-        if let syn::FnArg::Typed(ref arg) = a {
-            types.push(arg.ty.clone());
-
-            if let syn::Pat::Ident(_) = &*arg.pat {
-                names.push(arg.pat.clone());
-            } else {
-                return Err(syn::Error::new(
-                    sig.span(),
-                    "Cannot memoize arbitrary patterns!",
-                ));
-            }
-        }
-    }
-    Ok((types, names))
-}
-
-#[cfg(test)]
-mod tests {}
+#[cfg(feature = "full")]
+pub use ::lru;