From d97e7d83c7634102a09a13a94ca95586da25f866 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 5 Dec 2019 09:51:35 -0700 Subject: [PATCH 1/3] feat(typed): Provide `as_str` methods Unlike `Deref` or adding `AsRef`, this allows us to decouple the lifetimes. --- src/component.rs | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/component.rs b/src/component.rs index ced2521..7abb225 100644 --- a/src/component.rs +++ b/src/component.rs @@ -77,10 +77,9 @@ pub enum FooterSeparator { __NonExhaustive, } -impl Deref for FooterSeparator { - type Target = str; - - fn deref(&self) -> &Self::Target { +impl FooterSeparator { + /// Access `str` representation of FooterSeparator + pub fn as_str(self) -> &'static str { match self { FooterSeparator::ColonSpace => ": ", FooterSeparator::SpacePound => " #", @@ -89,6 +88,14 @@ impl Deref for FooterSeparator { } } +impl Deref for FooterSeparator { + type Target = str; + + fn deref(&self) -> &Self::Target { + self.as_str() + } +} + impl fmt::Display for FooterSeparator { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self) @@ -119,13 +126,18 @@ macro_rules! components { pub fn new(value: &'a str) -> Self { $ty(value) } + + /// Access `str` representation of $ty + pub fn as_str(&self) -> &'a str { + &self.0 + } } impl Deref for $ty<'_> { type Target = str; fn deref(&self) -> &Self::Target { - &self.0 + self.as_str() } } @@ -156,13 +168,18 @@ macro_rules! unicase_components { pub fn new(value: &'a str) -> Self { $ty(unicase::UniCase::new(value)) } + + /// Access `str` representation of $ty + pub fn as_str(&self) -> &'a str { + &self.0.into_inner() + } } impl Deref for $ty<'_> { type Target = str; fn deref(&self) -> &Self::Target { - &self.0.into_inner() + self.as_str() } } From 25e147ac6bef6339fe4d169a0d04d37ec6700e10 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 5 Dec 2019 09:48:12 -0700 Subject: [PATCH 2/3] fix(simple): Extend lifetimes Previously, `Simple` would return values whose lifetimes were tied to `self` but really all the lifetimes are tied to the original `str` which is longer than `self`. This also validates that users get the correct lifetimes from `as_str` with `Typed`. --- src/commit/simple.rs | 35 +++++++++++++++++------------------ src/component.rs | 2 +- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/commit/simple.rs b/src/commit/simple.rs index 566e2a0..4db2cd4 100644 --- a/src/commit/simple.rs +++ b/src/commit/simple.rs @@ -1,22 +1,21 @@ //! Conventional Commit implementations. use crate::{Commit, SimpleFooter}; -use std::ops::Deref; /// The weakly-typed variant of a commit. -pub trait Simple { +pub trait Simple<'a> { /// The type of the commit. - fn type_(&self) -> &str; + fn type_(&self) -> &'a str; /// The optional scope of the commit. - fn scope(&self) -> Option<&str>; + fn scope(&self) -> Option<&'a str>; /// The commit description. - fn description(&self) -> &str; + fn description(&self) -> &'a str; /// The commit body, containing a more detailed explanation of the commit /// changes. - fn body(&self) -> Option<&str>; + fn body(&self) -> Option<&'a str>; /// A flag to signal that the commit contains breaking changes. /// @@ -39,34 +38,34 @@ pub trait Simple { /// requiring whitespace before newlines. /// /// See: - fn footers(&self) -> Vec>; + fn footers(&self) -> Vec>; } -impl Simple for Commit<'_> { - fn type_(&self) -> &str { - &self.ty +impl<'a> Simple<'a> for Commit<'a> { + fn type_(&self) -> &'a str { + self.ty.as_str() } - fn scope(&self) -> Option<&str> { - self.scope.as_ref().map(Deref::deref) + fn scope(&self) -> Option<&'a str> { + self.scope.as_ref().map(|s| s.as_str()) } - fn description(&self) -> &str { - &self.description + fn description(&self) -> &'a str { + self.description.as_str() } - fn body(&self) -> Option<&str> { - self.body.as_ref().map(Deref::deref) + fn body(&self) -> Option<&'a str> { + self.body.as_ref().map(|s| s.as_str()) } fn breaking(&self) -> bool { self.breaking } - fn footers(&self) -> Vec> { + fn footers(&self) -> Vec> { self.footers .iter() - .map(|footer| SimpleFooter { footer }) + .map(|footer| SimpleFooter { footer: *footer }) .collect::>() } } diff --git a/src/component.rs b/src/component.rs index 7abb225..cc399ce 100644 --- a/src/component.rs +++ b/src/component.rs @@ -44,7 +44,7 @@ impl<'a> Footer<'a> { /// values of its components. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub struct SimpleFooter<'a> { - pub(crate) footer: &'a Footer<'a>, + pub(crate) footer: Footer<'a>, } impl<'a> SimpleFooter<'a> { From c9c4e40481a0d4f031d4f39c39df9c65d3b12b1b Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 5 Dec 2019 10:04:09 -0700 Subject: [PATCH 3/3] chore: Fix hidden module's docs --- src/commit/typed.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/commit/typed.rs b/src/commit/typed.rs index cc64f47..33ca5da 100644 --- a/src/commit/typed.rs +++ b/src/commit/typed.rs @@ -1,6 +1,4 @@ //! Conventional Commit implementations. -//! Conventional Commit implementations. -//! Conventional Commit implementations. use crate::typed::{Body, Description, Footer, Scope, Type}; use crate::Commit;