I am trying to write a simple TV-episode file renamer in Rust.
A filename is parsed, and might be one of several types (date-based, season/episode-number based etc). This parsed file is then turned into a "populated file" with data from a database (which is then formatted into a new filename)
Initially I tried having the parse
method take a filename and return an enum variant:
enum ParsedFile{
DateBased{series: String, date: Date},
SeasonBased{series: String, season: i32, episode: i32},
// etc
}
fn parse(fname:&str) -> Option<ParsedFile>{
...
}
This worked fine, however the methods to take the ParsedFile
and do different things for each episode became messy
For example, to separate the ParsedFile->PopulatedFile
translation into separate methods, I have to match the variants, then destructure this in the method
struct PopulatedFile {
seriesname: String,
season: i32,
episode: i32,
episodename: String,
airdate: Date,
}
fn _populate_seasonbased(file: ParsedFile) -> Result<PopulatedFile, TvdbError>{
// can't just access file.season or file.episode, have to destructure enum again
}
fn populate(f: ParsedFile) -> Result<PopulatedFile, TvdbError> {
return match f {
ParsedFile::DateBased{..} =>
_populate_datebased(f),
// ...
}
}
This seemed really clunky, and I'm sure there must be a better way.
It would be nicer to have each episode type as a separate struct, e.g:
struct DateBased{
series: String,
date: Date
}
struct SeasonBased{
series: String,
season: i32,
episode: i32
}
..then I could, say, implement a ToPopulatedFile
trait for each episode type. However I couldn't find a way to write the parse
method in this example (i.e write a method which might return a DateBased
struct or a SeasonBased
struct)
Is there a good way to structure this?
You could design a solution around trait
, but it would probably be much more work than simply adapting your current solution slightly:
struct DateBased{
series: String,
date: Date
}
struct SeasonBased{
series: String,
season: i32,
episode: i32
}
enum ParsedFile{
Date(DateBased),
Season(SeasonBased),
// etc
}
fn _populate_datebased(file: DateBased) -> Result<PopulatedFile, TvdbError>;
fn _populate_seasonbased(file: SeasonBased) -> Result<PopulatedFile, TvdbError>;
fn populate(f: ParsedFile) -> Result<PopulatedFile, TvdbError> {
return match f {
ParsedFile::Date(d) => _populate_datebased(d),
// ...
}
}
You can combine enum
and struct
in Rust, and I personally find it worth it to put name on things specifically because it allows manipulating them more easily.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With