fn parse_line(&mut self, mut line: &str) -> Result<(), ParsingError> {
        // Canonicalize lines.
        line = line.trim();
        if line.is_empty() {
            return Ok(());
        }

        // Skip comments.
        if line.starts_with('#') {
            return Ok(());
        // Handle new section.
        } else if line.starts_with('[') && line.ends_with(']') {
            // Close off existing section.
            self.flush()?;

            // Update the state.
            self.state = match line[1..line.len() - 1].trim() {
                // Global settings.
                "settings" => ParserState::GlobalSettings,
                // Default tag settings.
                "tag default" => ParserState::TagSettings(String::new()),
                // Tag specific settings.
                title if title.starts_with("tag ")
                    => ParserState::TagSettings(
                        // Take the part representing the tag name, following `tag ` in the section
                        // name.
                        title["tag ".len()..].trim_start().to_string()
                    ),
                // Otherwise, it must be a card.
                title if title.starts_with("card ")
                    => ParserState::Card(
                        // Take the part representing the card ID, following `card ` in the section
                        // name.
                        title["card ".len()..].trim_start().to_string()
                    ),
                _ => return Err(ParsingError::Other("unknown section")),
            };

            return Ok(());
        }

        match self.state {
            ParserState::GlobalSettings => {
                // Read key-value pair.
                let (key, value) = key_value(line)?;

                // Update global settings.
                match key {
                    "max new queue" => self.deck.settings.max_new_queue = value.parse()?,
                    "max new daily" => self.deck.settings.max_new_daily = value.parse()?,
                    "min new probability" => self.deck.settings.min_new_probability = value.parse()?,
                    _ => return Err(ParsingError::Other("unknown key")),
                }
            },
            ParserState::TagSettings(..) => {
                // Read key-value pair.
                let (key, value) = key_value(line)?;

                // Update tag settings.
                match key {
                    "INHERIT" => self.current_tag_settings = self.deck.tag_settings
                        .get(value)
                        .ok_or(ParsingError::Other("cannot inherit nonexistent settings"))?
                        .clone(),
                    "learning intervals"
                        => self.current_tag_settings.learning_intervals = parse_list(value, parse_duration)?,
                    "learning interval progressions"
                        => self.current_tag_settings.learning_interval_progressions = to_score_array(parse_list(value, str::parse)?)?,
                    "relearning intervals"
                        => self.current_tag_settings.relearning_intervals = parse_list(value, parse_duration)?,
                    "relearning interval progressions"
                        => self.current_tag_settings.relearning_interval_progressions = to_score_array(parse_list(value, str::parse)?)?,
                    "max interval" => self.current_tag_settings.max_interval = parse_duration(value)?,
                    "min interval increase"
                        => self.current_tag_settings.min_interval_increase = parse_duration(value)?,
                    "starting ease" => self.current_tag_settings.starting_ease = value.parse()?,
                    "min ease" => self.current_tag_settings.min_ease = value.parse()?,
                    "max ease" => self.current_tag_settings.max_ease = value.parse()?,
                    "ease increase"
                        => self.current_tag_settings.ease_increase = to_score_array(parse_list(value, str::parse)?)?,
                    "interval modifier" => self.current_tag_settings.interval_modifier = value.parse()?,
                    "score modifiers"
                        => self.current_tag_settings.score_modifiers = to_score_array(parse_list(value, str::parse)?)?,
                    "priority modifiers"
                        => self.current_tag_settings.priority_modifiers = to_score_array(parse_list(value, str::parse)?)?,
                    "score weight"
                        => self.current_tag_settings.score_weight = value.parse()?,
                    "familiarity delta"
                        => self.current_tag_settings.familiarity_delta = value.parse()?,
                    "max familiarity"
                        => self.current_tag_settings.max_familiarity = value.parse()?,
                    "min familiarity"
                        => self.current_tag_settings.min_familiarity = value.parse()?,
                    "desired retention rate"
                        => self.current_tag_settings.desired_retention_rate = value.parse()?,
                    _ => return Err(ParsingError::Other("unknown key")),
                }
            },
            ParserState::Card(..) => {
                // Read key-value pair.
                let (key, value) = key_value(line)?;

                // Update current card.
                match key {
                    "pdf" => self.current_card.view.extend(value.split(',').map(|x| x.trim().into()).map(cards::View::Pdf)),
                    "sh" => self.current_card.view.push(cards::View::Command(cards::Command(value.to_string()))),
                    "tags" => self.current_card.tags.extend(value.split(',').map(|x| x.trim().to_string())),
                    "max interval" => self.current_card.max_interval = parse_duration(value)?,
                    "priority" => {
                        // Parse the priority
                        let priority = value.parse::<cards::Priority>()? - 1;
                        // Handle invalid priorities.
                        if priority > 4 {
                            return Err(ParsingError::Other("invalid priority value; must be 1-5"));
                        }
                        // Update priority.
                        self.current_card.priority = priority;
                    },
                    _ => return Err(ParsingError::Other("unknown key")),
                }
            },
            // TODO: Somehow, this is not unreachable. Try to parse a random file.
            ParserState::Flushed => unreachable!(),
        }

        Ok(())
    }
/// Parse a single line and update state accordingly.
Parse a single line and update state accordingly.
Parse a single line and update state accordingly .
fn parse_line(&mut self, mut line: &str) -> Result<(), ParsingError> {
        // Canonicalize lines.
        line = line.trim();
        if line.is_empty() {
            return Ok(());
        }
        // Skip comments.
        if line.starts_with('#') {
            return Ok(());
        // Handle new section.
        } else if line.starts_with('[') && line.ends_with(']') {
            // Close off existing section.
            self.flush()?;
            // Update the state.
            self.state = match line[1..line.len() - 1].trim() {
                // Global settings.
                "settings" => ParserState::GlobalSettings,
                // Default tag settings.
                "tag default" => ParserState::TagSettings(String::new()),
                // Tag specific settings.
                title if title.starts_with("tag ")
                    => ParserState::TagSettings(
                        // Take the part representing the tag name, following `tag ` in the section
                        // name.
                        title["tag ".len()..].trim_start().to_string()
                    ),
                // Otherwise, it must be a card.
                title if title.starts_with("card ")
                    => ParserState::Card(
                        // Take the part representing the card ID, following `card ` in the section
                        // name.
                        title["card ".len()..].trim_start().to_string()
                    ),
                _ => return Err(ParsingError::Other("unknown section")),
            };
            return Ok(());
        }
        match self.state {
            ParserState::GlobalSettings => {
                // Read key-value pair.
                let (key, value) = key_value(line)?;
                // Update global settings.
                match key {
                    "max new queue" => self.deck.settings.max_new_queue = value.parse()?,
                    "max new daily" => self.deck.settings.max_new_daily = value.parse()?,
                    "min new probability" => self.deck.settings.min_new_probability = value.parse()?,
                    _ => return Err(ParsingError::Other("unknown key")),
                }
            },
            ParserState::TagSettings(..) => {
                // Read key-value pair.
                let (key, value) = key_value(line)?;
                // Update tag settings.
                match key {
                    "INHERIT" => self.current_tag_settings = self.deck.tag_settings
                        .get(value)
                        .ok_or(ParsingError::Other("cannot inherit nonexistent settings"))?
                        .clone(),
                    "learning intervals"
                        => self.current_tag_settings.learning_intervals = parse_list(value, parse_duration)?,
                    "learning interval progressions"
                        => self.current_tag_settings.learning_interval_progressions = to_score_array(parse_list(value, str::parse)?)?,
                    "relearning intervals"
                        => self.current_tag_settings.relearning_intervals = parse_list(value, parse_duration)?,
                    "relearning interval progressions"
                        => self.current_tag_settings.relearning_interval_progressions = to_score_array(parse_list(value, str::parse)?)?,
                    "max interval" => self.current_tag_settings.max_interval = parse_duration(value)?,
                    "min interval increase"
                        => self.current_tag_settings.min_interval_increase = parse_duration(value)?,
                    "starting ease" => self.current_tag_settings.starting_ease = value.parse()?,
                    "min ease" => self.current_tag_settings.min_ease = value.parse()?,
                    "max ease" => self.current_tag_settings.max_ease = value.parse()?,
                    "ease increase"
                        => self.current_tag_settings.ease_increase = to_score_array(parse_list(value, str::parse)?)?,
                    "interval modifier" => self.current_tag_settings.interval_modifier = value.parse()?,
                    "score modifiers"
                        => self.current_tag_settings.score_modifiers = to_score_array(parse_list(value, str::parse)?)?,
                    "priority modifiers"
                        => self.current_tag_settings.priority_modifiers = to_score_array(parse_list(value, str::parse)?)?,
                    "score weight"
                        => self.current_tag_settings.score_weight = value.parse()?,
                    "familiarity delta"
                        => self.current_tag_settings.familiarity_delta = value.parse()?,
                    "max familiarity"
                        => self.current_tag_settings.max_familiarity = value.parse()?,
                    "min familiarity"
                        => self.current_tag_settings.min_familiarity = value.parse()?,
                    "desired retention rate"
                        => self.current_tag_settings.desired_retention_rate = value.parse()?,
                    _ => return Err(ParsingError::Other("unknown key")),
                }
            },
            ParserState::Card(..) => {
                // Read key-value pair.
                let (key, value) = key_value(line)?;
                // Update current card.
                match key {
                    "pdf" => self.current_card.view.extend(value.split(',').map(|x| x.trim().into()).map(cards::View::Pdf)),
                    "sh" => self.current_card.view.push(cards::View::Command(cards::Command(value.to_string()))),
                    "tags" => self.current_card.tags.extend(value.split(',').map(|x| x.trim().to_string())),
                    "max interval" => self.current_card.max_interval = parse_duration(value)?,
                    "priority" => {
                        // Parse the priority
                        let priority = value.parse::<cards::Priority>()? - 1;
                        // Handle invalid priorities.
                        if priority > 4 {
                            return Err(ParsingError::Other("invalid priority value; must be 1-5"));
                        }
                        // Update priority.
                        self.current_card.priority = priority;
                    },
                    _ => return Err(ParsingError::Other("unknown key")),
                }
            },
            // TODO: Somehow, this is not unreachable. Try to parse a random file.
            ParserState::Flushed => unreachable!(),
        }
        Ok(())
    }
fn parse_line ( & mut self , mut line : & str ) -> Result < ( ) , ParsingError > { // Canonicalize lines. line = line . trim ( ) ; if line . is_empty ( ) { return Ok ( ( ) ) ; } // Skip comments. if line . starts_with ( '#' ) { return Ok ( ( ) ) ; // Handle new section. } else if line . starts_with ( '[' ) && line . ends_with ( ']' ) { // Close off existing section. self . flush ( ) ? ; // Update the state. self . state = match line [ 1 .. line . len ( ) - 1 ] . trim ( ) { // Global settings. " " => ParserState :: GlobalSettings , // Default tag settings. " " => ParserState :: TagSettings ( String :: new ( ) ) , // Tag specific settings. title if title . starts_with ( " " ) => ParserState :: TagSettings ( // Take the part representing the tag name, following `tag ` in the section // name. title [ " " . len ( ) .. ] . trim_start ( ) . to_string ( ) ) , // Otherwise, it must be a card. title if title . starts_with ( " " ) => ParserState :: Card ( // Take the part representing the card ID, following `card ` in the section // name. title [ " " . len ( ) .. ] . trim_start ( ) . to_string ( ) ) , _ => return Err ( ParsingError :: Other ( " " ) ) , } ; return Ok ( ( ) ) ; } match self . state { ParserState :: GlobalSettings => { // Read key-value pair. let ( key , value ) = key_value ( line ) ? ; // Update global settings. match key { " " => self . deck . settings . max_new_queue = value . parse ( ) ? , " " => self . deck . settings . max_new_daily = value . parse ( ) ? , " " => self . deck . settings . min_new_probability = value . parse ( ) ? , _ => return Err ( ParsingError :: Other ( " " ) ) , } } , ParserState :: TagSettings ( .. ) => { // Read key-value pair. let ( key , value ) = key_value ( line ) ? ; // Update tag settings. match key { " " => self . current_tag_settings = self . deck . tag_settings . get ( value ) . ok_or ( ParsingError :: Other ( " " ) ) ? . clone ( ) , " " => self . current_tag_settings . learning_intervals = parse_list ( value , parse_duration ) ? , " " => self . current_tag_settings . learning_interval_progressions = to_score_array ( parse_list ( value , str :: parse ) ? ) ? , " " => self . current_tag_settings . relearning_intervals = parse_list ( value , parse_duration ) ? , " " => self . current_tag_settings . relearning_interval_progressions = to_score_array ( parse_list ( value , str :: parse ) ? ) ? , " " => self . current_tag_settings . max_interval = parse_duration ( value ) ? , " " => self . current_tag_settings . min_interval_increase = parse_duration ( value ) ? , " " => self . current_tag_settings . starting_ease = value . parse ( ) ? , " " => self . current_tag_settings . min_ease = value . parse ( ) ? , " " => self . current_tag_settings . max_ease = value . parse ( ) ? , " " => self . current_tag_settings . ease_increase = to_score_array ( parse_list ( value , str :: parse ) ? ) ? , " " => self . current_tag_settings . interval_modifier = value . parse ( ) ? , " " => self . current_tag_settings . score_modifiers = to_score_array ( parse_list ( value , str :: parse ) ? ) ? , " " => self . current_tag_settings . priority_modifiers = to_score_array ( parse_list ( value , str :: parse ) ? ) ? , " " => self . current_tag_settings . score_weight = value . parse ( ) ? , " " => self . current_tag_settings . familiarity_delta = value . parse ( ) ? , " " => self . current_tag_settings . max_familiarity = value . parse ( ) ? , " " => self . current_tag_settings . min_familiarity = value . parse ( ) ? , " " => self . current_tag_settings . desired_retention_rate = value . parse ( ) ? , _ => return Err ( ParsingError :: Other ( " " ) ) , } } , ParserState :: Card ( .. ) => { // Read key-value pair. let ( key , value ) = key_value ( line ) ? ; // Update current card. match key { " " => self . current_card . view . extend ( value . split ( ',' ) . map ( | x | x . trim ( ) . into ( ) ) . map ( cards :: View :: Pdf ) ) , " " => self . current_card . view . push ( cards :: View :: Command ( cards :: Command ( value . to_string ( ) ) ) ) , " " => self . current_card . tags . extend ( value . split ( ',' ) . map ( | x | x . trim ( ) . to_string ( ) ) ) , " " => self . current_card . max_interval = parse_duration ( value ) ? , " " => { // Parse the priority let priority = value . parse :: < cards :: Priority > ( ) ? - 1 ; // Handle invalid priorities. if priority > 4 { return Err ( ParsingError :: Other ( " " ) ) ; } // Update priority. self . current_card . priority = priority ; } , _ => return Err ( ParsingError :: Other ( " " ) ) , } } , // TODO: Somehow, this is not unreachable. Try to parse a random file. ParserState :: Flushed => unreachable ! ( ) , } Ok ( ( ) ) }
Parse a single line and update state accordingly.
Parse a single line and update state accordingly .
&mut self
line
&str
&mut self
line
&str