diff --git a/derive/src/generate/generate_fn.rs b/derive/src/generate/generate_fn.rs index b42b658..ff44ede 100644 --- a/derive/src/generate/generate_fn.rs +++ b/derive/src/generate/generate_fn.rs @@ -24,21 +24,7 @@ impl<'a, 'b> FnBuilder<'a, 'b> { } } - #[cfg(test)] - #[doc(hidden)] - #[allow(unused)] - pub fn for_test() -> Self { - Self { - generate: None, - name: String::new(), - lifetime_and_generics: Vec::new(), - self_arg: FnSelfArg::None, - args: Vec::new(), - return_type: None, - } - } - - /// Add a generic parameter. Keep in mind that this is *not* a valid lifetime. + /// Add a generic parameter. Keep in mind that will *not* work for lifetimes. /// /// `dependencies` are the optional dependencies of the parameter. /// @@ -61,21 +47,53 @@ impl<'a, 'b> FnBuilder<'a, 'b> { self } + /// Set the value for `self`. See [FnSelfArg] for more information. + /// + /// ```ignore + /// let mut builder: FnBuilder = ...; + /// // static function by default + /// builder.with_self_arg(FnSelfArg::RefSelf); // fn foo(&self) + /// ``` pub fn with_self_arg(mut self, self_arg: FnSelfArg) -> Self { self.self_arg = self_arg; self } + /// Add an argument with a `name` and a `ty`. + /// + /// ```ignore + /// let mut builder: FnBuilder = ...; + /// // fn foo(); + /// builder + /// .with_arg("a", "u32") // fn foo(a: u32) + /// .with_arg("b", "u32"); // fn foo(a: u32, b: u32) + /// ``` pub fn with_arg(mut self, name: impl Into, ty: impl Into) -> Self { self.args.push((name.into(), ty.into())); self } + /// Set the return type for the function. By default the function will have no return type. + /// + /// ```ignore + /// let mut builder: FnBuilder = ...; + /// // fn foo() + /// builder.with_return_type("u32"); // fn foo() -> u32 + /// ``` pub fn with_return_type(mut self, ret_type: impl Into) -> Self { self.return_type = Some(ret_type.into()); self } + /// Complete the function definition. This function takes a callback that will form the body of the function. + /// + /// ```ignore + /// let mut builder: FnBuilder = ...; + /// // fn foo() + /// builder.body(|b| { + /// b.push_parsed("println!(\"hello world\");"); + /// }); + /// ``` pub fn body(self, body_builder: impl FnOnce(&mut StreamBuilder)) { let FnBuilder { mut generate, @@ -141,9 +159,20 @@ impl<'a, 'b> FnBuilder<'a, 'b> { } } +/// The `self` argument of a function +#[allow(dead_code)] pub enum FnSelfArg { + /// No `self` argument. The function will be a static function. None, + + /// `self`. The function will consume self. + TakeSelf, + + /// `&self`. The function will take self by reference. RefSelf, + + /// `&mut self`. The function will take self by mutable reference. + MutSelf, } impl FnSelfArg { @@ -151,10 +180,18 @@ impl FnSelfArg { let mut builder = StreamBuilder::new(); match self { Self::None => return None, + Self::TakeSelf => { + builder.ident_str("self"); + } Self::RefSelf => { builder.punct('&'); builder.ident_str("self"); } + Self::MutSelf => { + builder.punct('&'); + builder.ident_str("mut"); + builder.ident_str("self"); + } } Some(builder) } diff --git a/derive/src/generate/generator.rs b/derive/src/generate/generator.rs index cf56fa6..b330476 100644 --- a/derive/src/generate/generator.rs +++ b/derive/src/generate/generator.rs @@ -24,18 +24,22 @@ impl Generator { } } + /// Return the name for the struct or enum that this is going to be implemented on. pub fn target_name(&self) -> &Ident { &self.name } + /// Generate an `for for ` implementation. See [ImplFor] for more information. pub fn impl_for<'a>(&'a mut self, trait_name: &str) -> ImplFor<'a> { ImplFor::new(self, trait_name) } + /// Generate an `for <'__de> for ` implementation. See [ImplFor] for more information. pub fn impl_for_with_de_lifetime<'a>(&'a mut self, trait_name: &str) -> ImplFor<'a> { ImplFor::new_with_de_lifetime(self, trait_name) } + /// Returns `true` if the struct or enum has lifetimes. pub fn has_lifetimes(&self) -> bool { self.generics .as_ref() @@ -43,8 +47,9 @@ impl Generator { .unwrap_or(false) } + /// Consume the contents of this generator. This *must* be called, or else the generator will panic on drop. pub fn take_stream(mut self) -> TokenStream { - std::mem::take(&mut self.stream.stream) + std::mem::take(&mut self.stream).stream } } diff --git a/derive/src/generate/impl_for.rs b/derive/src/generate/impl_for.rs index 753f206..7652848 100644 --- a/derive/src/generate/impl_for.rs +++ b/derive/src/generate/impl_for.rs @@ -58,6 +58,7 @@ impl<'a> ImplFor<'a> { Self { generator, group } } + /// Add a function to the trait implementation pub fn generate_fn<'b>(&'b mut self, name: &str) -> FnBuilder<'a, 'b> { FnBuilder::new(self, name) } diff --git a/derive/src/generate/stream_builder.rs b/derive/src/generate/stream_builder.rs index 8331286..3ee6566 100644 --- a/derive/src/generate/stream_builder.rs +++ b/derive/src/generate/stream_builder.rs @@ -3,6 +3,7 @@ use crate::prelude::{ }; use std::str::FromStr; +/// A helper struct build around a [TokenStream] to make it easier to build code. #[must_use] #[derive(Default)] pub struct StreamBuilder { @@ -10,24 +11,31 @@ pub struct StreamBuilder { } impl StreamBuilder { + /// Generate a new StreamBuilder pub fn new() -> Self { Self { stream: TokenStream::new(), } } + /// Add multiple `TokenTree` items to the stream. pub fn extend(&mut self, item: impl IntoIterator) { self.stream.extend(item); } + /// Append another StreamBuilder to the current StreamBuilder. pub fn append(&mut self, builder: StreamBuilder) { self.stream.extend(builder.stream); } + /// Push a single token to the stream. pub fn push(&mut self, item: impl Into) { self.stream.extend([item.into()]); } + /// Attempt to parse the given string as valid Rust code, and append the parsed result to the internal stream. + /// + /// Currently panics if the string could not be parsed as valid Rust code. pub fn push_parsed(&mut self, item: impl AsRef) { self.stream .extend(TokenStream::from_str(item.as_ref()).unwrap_or_else(|e| { @@ -39,10 +47,12 @@ impl StreamBuilder { })); } + /// Push a single ident to the stream. An ident is any worse that a code file may contain, e.g. `fn`, `struct`, `where`, names of functions and structs, etc. pub fn ident(&mut self, ident: Ident) { self.stream.extend([TokenTree::Ident(ident)]); } + /// Push a single ident to the stream. An ident is any worse that a code file may contain, e.g. `fn`, `struct`, `where`, names of functions and structs, etc. pub fn ident_str(&mut self, ident: impl AsRef) { self.stream.extend([TokenTree::Ident(Ident::new( ident.as_ref(), @@ -50,6 +60,9 @@ impl StreamBuilder { ))]); } + /// Add a group. A group is any block surrounded by `{ .. }`, `[ .. ]` or `( .. )`. + /// + /// `delim` indicates which group it is. The `inner` callback is used to fill the contents of the group. pub fn group(&mut self, delim: Delimiter, inner: impl FnOnce(&mut StreamBuilder)) { let mut stream = StreamBuilder::new(); inner(&mut stream); @@ -57,11 +70,18 @@ impl StreamBuilder { .extend([TokenTree::Group(Group::new(delim, stream.stream))]); } + /// Add a single punctuation to the stream. Puncts are single-character tokens like `.`, `<`, `#`, etc + /// + /// Note that this should not be used for multi-punct constructions like `::` or `->`. For that use [puncts] instead. pub fn punct(&mut self, p: char) { self.stream .extend([TokenTree::Punct(Punct::new(p, Spacing::Alone))]); } + /// Add multiple punctuations to the stream. Multi punct tokens are e.g. `::`, `->` and `=>`. + /// + /// Note that this is the only way to add multi punct tokens. + /// If you were to use [punct] to insert `->` it would be inserted as `-` and then `>`, and not form a single token. Rust would interpret this as a "minus sign and then a greater than sign", not as a single arrow. pub fn puncts(&mut self, puncts: &str) { self.stream.extend( puncts @@ -70,12 +90,29 @@ impl StreamBuilder { ); } + /// Add a lifetime to the stream. + /// + /// Note that this is the only way to add lifetimes, if you were to do: + /// ```ignore + /// builder.punct('\''); + /// builder.ident_str("static"); + /// ``` + /// It would not add `'static`, but instead it would add `' static` as seperate tokens, and the lifetime would not work. pub fn lifetime(&mut self, lt: Ident) { self.stream.extend([ TokenTree::Punct(Punct::new('\'', Spacing::Joint)), TokenTree::Ident(lt), ]); } + + /// Add a lifetime to the stream. + /// + /// Note that this is the only way to add lifetimes, if you were to do: + /// ```ignore + /// builder.punct('\''); + /// builder.ident_str("static"); + /// ``` + /// It would not add `'static`, but instead it would add `' static` as seperate tokens, and the lifetime would not work. pub fn lifetime_str(&mut self, lt: &str) { self.stream.extend([ TokenTree::Punct(Punct::new('\'', Spacing::Joint)), @@ -83,21 +120,25 @@ impl StreamBuilder { ]); } + /// Add a literal string (`&'static str`) to the stream. pub fn lit_str(&mut self, str: impl AsRef) { self.stream .extend([TokenTree::Literal(Literal::string(str.as_ref()))]); } + /// Add an `u32` value to the stream. pub fn lit_u32(&mut self, val: u32) { self.stream .extend([TokenTree::Literal(Literal::u32_unsuffixed(val))]); } + /// Add an `usize` value to the stream. pub fn lit_usize(&mut self, val: usize) { self.stream .extend([TokenTree::Literal(Literal::usize_unsuffixed(val))]); } + /// Set the given span on all tokens in the stream. This span is used by rust for e.g. compiler errors, to indicate the position of the error. pub fn set_span_on_all_tokens(&mut self, span: Span) { self.stream = std::mem::take(&mut self.stream) .into_iter()