mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-08-24 18:06:42 +02:00
hide the implementation of Tag
This commit is contained in:
parent
ff23c9148b
commit
0e60bcedaf
3 changed files with 49 additions and 22 deletions
|
@ -13,6 +13,4 @@ pub use status::Status;
|
|||
pub use tag::{Tag, INVALID_TAG_CHARACTERS};
|
||||
pub use task::{Task, TaskMut};
|
||||
|
||||
use tag::SyntheticTag;
|
||||
|
||||
pub type Timestamp = DateTime<Utc>;
|
||||
|
|
|
@ -10,7 +10,11 @@ use std::str::FromStr;
|
|||
/// This definition is based on [that of
|
||||
/// TaskWarrior](https://github.com/GothenburgBitFactory/taskwarrior/blob/663c6575ceca5bd0135ae884879339dac89d3142/src/Lexer.cpp#L146-L164).
|
||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
|
||||
pub enum Tag {
|
||||
pub struct Tag(TagInner);
|
||||
|
||||
/// Inner type to hide the implementation
|
||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
|
||||
pub(super) enum TagInner {
|
||||
User(String),
|
||||
Synthetic(SyntheticTag),
|
||||
}
|
||||
|
@ -18,7 +22,7 @@ pub enum Tag {
|
|||
pub const INVALID_TAG_CHARACTERS: &str = "+-*/(<>^! %=~";
|
||||
|
||||
impl Tag {
|
||||
fn from_str(value: &str) -> Result<Tag, anyhow::Error> {
|
||||
pub fn from_str(value: &str) -> Result<Tag, anyhow::Error> {
|
||||
fn err(value: &str) -> Result<Tag, anyhow::Error> {
|
||||
anyhow::bail!("invalid tag {:?}", value)
|
||||
}
|
||||
|
@ -26,7 +30,7 @@ impl Tag {
|
|||
// first, look for synthetic tags
|
||||
if value.chars().all(|c| c.is_ascii_uppercase()) {
|
||||
if let Ok(st) = SyntheticTag::from_str(value) {
|
||||
return Ok(Self::Synthetic(st));
|
||||
return Ok(Self(TagInner::Synthetic(st)));
|
||||
}
|
||||
// all uppercase, but not a valid synthetic tag
|
||||
return err(value);
|
||||
|
@ -46,7 +50,29 @@ impl Tag {
|
|||
{
|
||||
return err(value);
|
||||
}
|
||||
Ok(Self::User(String::from(value)))
|
||||
Ok(Self(TagInner::User(String::from(value))))
|
||||
}
|
||||
|
||||
/// True if this tag is a synthetic tag
|
||||
pub fn is_synthetic(&self) -> bool {
|
||||
if let TagInner::Synthetic(_) = self.0 {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// True if this tag is a user-provided tag (not synthetic)
|
||||
pub fn is_user(&self) -> bool {
|
||||
!self.is_synthetic()
|
||||
}
|
||||
|
||||
pub(super) fn inner(&self) -> &TagInner {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub(super) fn from_inner(inner: TagInner) -> Self {
|
||||
Self(inner)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,22 +94,24 @@ impl TryFrom<&String> for Tag {
|
|||
|
||||
impl fmt::Display for Tag {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::User(s) => s.fmt(f),
|
||||
Self::Synthetic(st) => st.as_ref().fmt(f),
|
||||
match &self.0 {
|
||||
TagInner::User(s) => s.fmt(f),
|
||||
TagInner::Synthetic(st) => st.as_ref().fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for Tag {
|
||||
fn as_ref(&self) -> &str {
|
||||
match self {
|
||||
Self::User(s) => s.as_ref(),
|
||||
Self::Synthetic(st) => st.as_ref(),
|
||||
match &self.0 {
|
||||
TagInner::User(s) => s.as_ref(),
|
||||
TagInner::Synthetic(st) => st.as_ref(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A synthetic tag, represented as an `enum`. This type is used directly by
|
||||
/// [`taskchampion::task::task`] for efficiency.
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
|
@ -97,7 +125,7 @@ impl AsRef<str> for Tag {
|
|||
strum_macros::EnumIter,
|
||||
)]
|
||||
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
|
||||
pub enum SyntheticTag {
|
||||
pub(super) enum SyntheticTag {
|
||||
Waiting,
|
||||
Active,
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use super::{Status, SyntheticTag, Tag};
|
||||
use super::tag::{SyntheticTag, TagInner};
|
||||
use super::{Status, Tag};
|
||||
use crate::replica::Replica;
|
||||
use crate::storage::TaskMap;
|
||||
use chrono::prelude::*;
|
||||
|
@ -100,9 +101,9 @@ impl Task {
|
|||
|
||||
/// Check if this task has the given tag
|
||||
pub fn has_tag(&self, tag: &Tag) -> bool {
|
||||
match tag {
|
||||
Tag::User(s) => self.taskmap.contains_key(&format!("tag.{}", s)),
|
||||
Tag::Synthetic(st) => self.has_synthetic_tag(st),
|
||||
match tag.inner() {
|
||||
TagInner::User(s) => self.taskmap.contains_key(&format!("tag.{}", s)),
|
||||
TagInner::Synthetic(st) => self.has_synthetic_tag(st),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,7 +125,7 @@ impl Task {
|
|||
.chain(
|
||||
SyntheticTag::iter()
|
||||
.filter(move |st| self.has_synthetic_tag(st))
|
||||
.map(|st| Tag::Synthetic(st)),
|
||||
.map(|st| Tag::from_inner(TagInner::Synthetic(st))),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -203,7 +204,7 @@ impl<'r> TaskMut<'r> {
|
|||
|
||||
/// Add a tag to this task. Does nothing if the tag is already present.
|
||||
pub fn add_tag(&mut self, tag: &Tag) -> anyhow::Result<()> {
|
||||
if let Tag::Synthetic(_) = tag {
|
||||
if tag.is_synthetic() {
|
||||
anyhow::bail!("Synthetic tags cannot be modified");
|
||||
}
|
||||
self.set_string(format!("tag.{}", tag), Some("".to_owned()))
|
||||
|
@ -211,7 +212,7 @@ impl<'r> TaskMut<'r> {
|
|||
|
||||
/// Remove a tag from this task. Does nothing if the tag is not present.
|
||||
pub fn remove_tag(&mut self, tag: &Tag) -> anyhow::Result<()> {
|
||||
if let Tag::Synthetic(_) = tag {
|
||||
if tag.is_synthetic() {
|
||||
anyhow::bail!("Synthetic tags cannot be modified");
|
||||
}
|
||||
self.set_string(format!("tag.{}", tag), None)
|
||||
|
@ -301,12 +302,12 @@ mod test {
|
|||
|
||||
/// Create a user tag, without checking its validity
|
||||
fn utag(name: &'static str) -> Tag {
|
||||
Tag::User(name.into())
|
||||
Tag::from_inner(TagInner::User(name.into()))
|
||||
}
|
||||
|
||||
/// Create a synthetic tag
|
||||
fn stag(synth: SyntheticTag) -> Tag {
|
||||
Tag::Synthetic(synth)
|
||||
Tag::from_inner(TagInner::Synthetic(synth))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue