Repository: astral-sh/ruff
File: crates/ruff_linter/src/settings/types.rs (Rust)

Code before:
            }
            (tokens[0].trim(), tokens[1].trim())
        };
        let extension = extension_str.into();
        let language = Language::from_str(language_str)?;
        Ok(Self {
            extension,
            language,
        })
    }
}

impl From<ExtensionPair> for (String, Language) {
    fn from(value: ExtensionPair) -> Self {
        (value.extension, value.language)
    }
}

#[derive(Debug, Clone, Default, CacheKey)]
pub struct ExtensionMapping(FxHashMap<String, Language>);

impl ExtensionMapping {
    /// Return the file extensions in the mapping.
    pub fn extensions(&self) -> Vec<&String> {
        self.0.keys().collect()
    }

    /// Return the [`Language`] for the given file.
    pub fn get(&self, path: &Path) -> Option<Language> {
        let ext = path.extension()?.to_str()?;
        self.0.get(ext).copied()
    }

    /// Return the [`Language`] for a given file extension.
    pub fn get_extension(&self, ext: &str) -> Option<Language> {
        self.0.get(ext).copied()
    }

    /// Return a mapped [`SourceType`] for a given path.
    pub fn get_source_type(&self, path: &Path) -> SourceType {
        match self.get(path) {
            None => SourceType::from(path),
            Some(language) => SourceType::from(language),
        }
    }

    /// Return a mapped [`SourceType`] for a given file extension.
    pub fn get_source_type_by_extension(&self, ext: &str) -> SourceType {
        match self.get_extension(ext) {
            None => SourceType::from_extension(ext),
            Some(language) => SourceType::from(language),

Review comment (suggestion):
I don't like creating a vec here, but couldn't figure out how to annotate this to just return `self.0.keys()`.

Code after:
            }
            (tokens[0].trim(), tokens[1].trim())
        };
        let extension = extension_str.into();
        let language = Language::from_str(language_str)?;
        Ok(Self {
            extension,
            language,
        })
    }
}

impl From<ExtensionPair> for (String, Language) {
    fn from(value: ExtensionPair) -> Self {
        (value.extension, value.language)
    }
}

#[derive(Debug, Clone, Default, CacheKey)]
pub struct ExtensionMapping(FxHashMap<String, Language>);

impl ExtensionMapping {
    /// Return the file extensions in the mapping.
    pub fn extensions(&self) -> impl Iterator<Item = &String> {
        self.0.keys()
    }

    /// Return the [`Language`] for the given file.
    pub fn get(&self, path: &Path) -> Option<Language> {
        let ext = path.extension()?.to_str()?;
        self.0.get(ext).copied()
    }

    /// Return the [`Language`] for a given file extension.
    pub fn get_extension(&self, ext: &str) -> Option<Language> {
        self.0.get(ext).copied()
    }

    /// Return a mapped [`SourceType`] for a given path.
    pub fn get_source_type(&self, path: &Path) -> SourceType {
        match self.get(path) {
            None => SourceType::from(path),
            Some(language) => SourceType::from(language),
        }
    }

    /// Return a mapped [`SourceType`] for a given file extension.
    pub fn get_source_type_by_extension(&self, ext: &str) -> SourceType {
        match self.get_extension(ext) {
            None => SourceType::from_extension(ext),
            Some(language) => SourceType::from(language),