/// Parse a string into a `Room`.
///
/// > Each room consists of an encrypted name (lowercase letters separated by dashes) >
/// followed by a dash, a sector ID, and a checksum in square brackets.
///
/// # Examples
///
/// `aaaaa-bbb-z-y-x-123[abxyz]`
/// `a-b-c-d-e-f-g-h-987[abcde]`
/// `not-a-real-room-404[oarel]`
/// `totally-real-room-200[decoy]`
// We could just /^([a-z]+(?:-[a-z]+)*)-(\d+)\[[a-z]+\]$/ but meh
Parse a string into a `Room`.
> Each room consists of an encrypted name (lowercase letters separated by dashes) >
followed by a dash, a sector ID, and a checksum in square brackets.
Parse a string into a ` Room ` . > Each room consists of an encrypted name ( lowercase letters separated by dashes ) > followed by a dash a sector ID and a checksum in square brackets .
fn from_str(s: &str) -> Result<Room, String> {
            let parse_error_for = |part, x| {
                match x {
                    Some(ch) => Err(format!("unexpected `{}` while parsing {}", ch, part)),
                    None     => Err(format!("parsing {} failed", part)),
                }
            };
            let mut iter = s.chars().peekable();
            let mut encrypted_name = String::with_capacity(s.len());
            let mut sector_id      = String::with_capacity(s.len());
            let mut checksum       = String::with_capacity(s.len());
            // parse the encrypted name
            loop {
                match iter.next() {
                    Some(ch) if is_ascii_lower(ch) => encrypted_name.push(ch),
                    Some(ch) if is_dash(ch) => match iter.peek() {
                        // we don't accept encrypted name beginning with a dash
                        _ if encrypted_name.len() == 0 => return parse_error_for("encrypted name", Some(ch)),
                        // if the next character is numeric then this dash (ch) is the delimiter
                        // between the encrypted name and sector ID.
                        Some(&next) if is_ascii_digit(next) => break,
                        // the encrypted name may contains dash but then we require the next
                        // character to be a letter
                        Some(&next) if is_ascii_lower(next) => encrypted_name.push(ch),
                        // this is unexpected, but we'll handle it at the next iteration.
                        _ => continue,
                    },
                    x => return parse_error_for("encrypted name", x),
                }
            }
            // parse the sector ID
            loop {
                match iter.next() {
                    Some(ch) if is_ascii_digit(ch) => sector_id.push(ch),
                    Some(ch) if is_left_square_bracket(ch) => break,
                    x => return parse_error_for("sector ID", x),
                }
            }
            // parse the checksum
            loop {
                match iter.next() {
                    Some(ch) if is_ascii_lower(ch) => checksum.push(ch),
                    Some(ch) if is_right_square_bracket(ch) => break,
                    x => return parse_error_for("checksum", x),
                }
            }
            // we're done parsing, don't allow the input to have more characters.
            if iter.peek().is_some() {
                return parse_error_for("room", iter.next());
            }
            Ok(Room {
                encrypted_name: RoomEncryptedName(encrypted_name),
                sector_id: sector_id.parse().unwrap(),
                checksum: checksum,
            })
        }
fn from_str ( s : & str ) -> Result < Room , String > { let parse_error_for = | part , x | { match x { Some ( ch ) => Err ( format ! ( " " ch part ) ) , None => Err ( format ! ( " " part ) ) , } } ; let mut iter = s . chars ( ) . peekable ( ) ; let mut encrypted_name = String :: with_capacity ( s . len ( ) ) ; let mut sector_id = String :: with_capacity ( s . len ( ) ) ; let mut checksum = String :: with_capacity ( s . len ( ) ) ; // parse the encrypted name loop { match iter . next ( ) { Some ( ch ) if is_ascii_lower ( ch ) => encrypted_name . push ( ch ) , Some ( ch ) if is_dash ( ch ) => match iter . peek ( ) { // we don't accept encrypted name beginning with a dash _ if encrypted_name . len ( ) == 0 => return parse_error_for ( " " , Some ( ch ) ) , // if the next character is numeric then this dash (ch) is the delimiter // between the encrypted name and sector ID. Some ( & next ) if is_ascii_digit ( next ) => break , // the encrypted name may contains dash but then we require the next // character to be a letter Some ( & next ) if is_ascii_lower ( next ) => encrypted_name . push ( ch ) , // this is unexpected, but we'll handle it at the next iteration. _ => continue , } , x => return parse_error_for ( " " , x ) , } } // parse the sector ID loop { match iter . next ( ) { Some ( ch ) if is_ascii_digit ( ch ) => sector_id . push ( ch ) , Some ( ch ) if is_left_square_bracket ( ch ) => break , x => return parse_error_for ( " " , x ) , } } // parse the checksum loop { match iter . next ( ) { Some ( ch ) if is_ascii_lower ( ch ) => checksum . push ( ch ) , Some ( ch ) if is_right_square_bracket ( ch ) => break , x => return parse_error_for ( " " , x ) , } } // we're done parsing, don't allow the input to have more characters. if iter . peek ( ) . is_some ( ) { return parse_error_for ( " " , iter . next ( ) ) ; } Ok ( Room { encrypted_name : RoomEncryptedName ( encrypted_name ) , sector_id : sector_id . parse ( ) . unwrap ( ) , checksum : checksum , } ) }
Parse a string into a `Room`.
Parse a string into a ` Room ` .
s
&str
examples
None