Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple return types from a method

Tags:

rust

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?

like image 840
dbr Avatar asked Aug 30 '15 11:08

dbr


1 Answers

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.

like image 72
Matthieu M. Avatar answered Oct 23 '22 14:10

Matthieu M.