Repository: astral-sh/ruff
File: crates/ruff_python_literal/src/format.rs (Rust)

Code before:
                nested = true;
                left.push(c);
                continue;
            } else if c == '}' {
                if nested {
                    nested = false;
                    left.push(c);
                    continue;
                }
                let (_, right) = text.split_at(idx + 1);
                let format_part = FormatString::parse_part_in_brackets(&left)?;
                return Ok((format_part, right));
            }
            left.push(c);
        }
        Err(FormatParseError::UnmatchedBracket)
    }

    fn parse_escaped_unicode_string(text: &str) -> Option<(&str, &str)> {
        text.strip_prefix("N{")?.find('}').map(|idx| {
            let end_idx = idx + 3; // 3 for "N{"
            (&text[..end_idx], &text[end_idx..])
        })
    }

    pub fn parse(text: &str, is_raw: bool) -> Result<Self, FormatParseError> {
        let mut cur_text: &str = text;
        let mut parts: Vec<FormatPart> = Vec::new();
        while !cur_text.is_empty() {
            cur_text = FormatString::parse_literal(cur_text, is_raw)
                .or_else(|_| FormatString::parse_spec(cur_text, AllowPlaceholderNesting::Yes))
                .map(|(part, new_text)| {
                    parts.push(part);
                    new_text
                })?;
        }
        Ok(FormatString {
            format_parts: parts,
        })
    }
}

pub trait FromTemplate<'a>: Sized {
    type Err;
    fn from_str(s: &'a str) -> Result<Self, Self::Err>;
}

impl<'a> FromTemplate<'a> for FormatString {
    type Err = FormatParseError;

    fn from_str(text: &'a str) -> Result<Self, Self::Err> {

Review comment (suggestion):
Instead of exposing this `parse` method, why don't we add a new `from_raw_str` constructor. I'm a bit confused why we have this trait to begin with since this is the only implementation of the trait. I'm also wondering if any of our other uses of `from_str` should consider whether the input is a raw string, but I think preserving both `from_str` and `from_raw_str` as the public API would help to guide users in that direction. We don't necessarily need to vet all the other uses here. What do you think?

Concretely, I'm suggesting something like this:


```suggestion
    fn parse(text: &str, is_raw: bool) -> Result<Self, FormatParseError> {
```

and 

```rust
pub trait FromTemplate<'a>: Sized {
    type Err;
    fn from_str(s: &'a str) -> Result<Self, Self::Err>;
    fn from_raw_str(s: &'a str) -> Result<Self, Self::Err>;
}

impl<'a> FromTemplate<'a> for FormatString {
    type Err = FormatParseError;

    fn from_str(text: &'a str) -> Result<Self, Self::Err> {
        FormatString::parse(text, false)
    }

    fn from_raw_str(text: &'a str) -> Result<Self, Self::Err> {
        FormatString::parse(text, true)
    }
}
```

or we could just delete the trait entirely:

```rust
impl FormatString {
    pub fn from_str(text: &str) -> Result<Self, FormatParseError> {
        FormatString::parse(text, false)
    }

    pub fn from_raw_str(text: &str) -> Result<Self, FormatParseError> {
        FormatString::parse(text, true)
    }
}
```

Code after:
                nested = true;
                left.push(c);
                continue;
            } else if c == '}' {
                if nested {
                    nested = false;
                    left.push(c);
                    continue;
                }
                let (_, right) = text.split_at(idx + 1);
                let format_part = FormatString::parse_part_in_brackets(&left)?;
                return Ok((format_part, right));
            }
            left.push(c);
        }
        Err(FormatParseError::UnmatchedBracket)
    }

    fn parse_escaped_unicode_string(text: &str) -> Option<(&str, &str)> {
        text.strip_prefix("N{")?.find('}').map(|idx| {
            let end_idx = idx + 3; // 3 for "N{"
            (&text[..end_idx], &text[end_idx..])
        })
    }

    fn parse(text: &str, is_raw: bool) -> Result<Self, FormatParseError> {
        let mut cur_text: &str = text;
        let mut parts: Vec<FormatPart> = Vec::new();
        while !cur_text.is_empty() {
            // Try to parse both literals and bracketed format parts until we
            // run out of text
            cur_text = FormatString::parse_literal(cur_text, is_raw)
                .or_else(|_| FormatString::parse_spec(cur_text, AllowPlaceholderNesting::Yes))
                .map(|(part, new_text)| {
                    parts.push(part);
                    new_text
                })?;
        }
        Ok(FormatString {
            format_parts: parts,
        })
    }
}

pub trait FromTemplate<'a>: Sized {
    type Err;
    fn from_str(s: &'a str) -> Result<Self, Self::Err>;
    fn from_raw_str(s: &'a str) -> Result<Self, Self::Err>;
}

impl<'a> FromTemplate<'a> for FormatString {