1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use crate::{error::Error, run::Run};
use clap::{Args, Subcommand};
use std::fmt::Debug;

/// Table of [`Args`] types to used in [`Field`].
pub trait ArgsTable {
    /// CLI arguments for text fields.
    type Text: Args;
    /// Genre fields.
    type Genre: Subcommand;
    /// CLI arguments for the picture field.
    type Picture: Args;
    /// CLI arguments for the comment field.
    type Comment: Args;
}

/// Field-specific subcommand.
#[derive(Debug, Subcommand)]
pub enum Field<Args>
where
    Args: ArgsTable,
    Args::Text: Debug,
    Args::Genre: Debug,
    Args::Comment: Debug,
    Args::Picture: Debug,
{
    /// Text field.
    #[clap(flatten)]
    Text(Text<Args>),
    /// Frame field.
    #[clap(flatten)]
    Frame(Frame<Args>),
}

impl<Args> Run for Field<Args>
where
    Args: ArgsTable,
    Args::Text: Debug,
    Args::Genre: Debug,
    Args::Comment: Debug,
    Args::Picture: Debug,
    Text<Args>: Run,
    Frame<Args>: Run,
{
    fn run(self) -> Result<(), Error> {
        match self {
            Field::Text(proc) => proc.run(),
            Field::Frame(proc) => proc.run(),
        }
    }
}

/// Text field subcommand.
#[derive(Debug, Subcommand)]
pub enum Text<Args: ArgsTable> {
    Title(Args::Text),
    Artist(Args::Text),
    Album(Args::Text),
    AlbumArtist(Args::Text),
    #[clap(flatten)]
    Genre(Args::Genre),
}

/// Frame field subcommand.
#[derive(Debug, Subcommand)]
pub enum Frame<Args: ArgsTable> {
    Comment(Args::Comment),
    Picture(Args::Picture),
}

impl<Args> Run for Frame<Args>
where
    Args: ArgsTable,
    Args::Comment: Run,
    Args::Picture: Run,
{
    fn run(self) -> Result<(), Error> {
        match self {
            Frame::Comment(proc) => proc.run(),
            Frame::Picture(proc) => proc.run(),
        }
    }
}