Repository: microsoft/edit
File: src/icu.rs (Rust)

Code before:
use std::ffi::{CStr, c_char};
use std::mem;
use std::mem::MaybeUninit;
use std::ops::Range;
use std::ptr::{null, null_mut};

use crate::arena::{Arena, ArenaString, scratch_arena};
use crate::buffer::TextBuffer;
use crate::unicode::Utf8Chars;
use crate::{apperr, arena_format, sys};

static mut ENCODINGS: Vec<EncodingInfo> = Vec::new();

pub struct EncodingInfo {
    pub name: &'static str,
    pub aliases: Vec<&'static str>,
}

/// Returns a list of encodings ICU supports.
pub fn get_available_encodings() -> &'static Vec<EncodingInfo> {
    // OnceCell for people that want to put it into a static.
    #[allow(static_mut_refs)]
    unsafe {
        if ENCODINGS.is_empty() {
            ENCODINGS.push(EncodingInfo { name: "UTF-8", aliases: vec![] });
            ENCODINGS.push(EncodingInfo { name: "UTF-8-BOM", aliases: vec![] });

            if let Ok(f) = init_if_needed() {
                let mut n = 0;
                loop {
                    let c_name = (f.ucnv_getAvailableName)(n);
                    if c_name.is_null() {
                        break;
                    }

                    let name = CStr::from_ptr(c_name).to_str().unwrap_unchecked();
                    // We have already pushed UTF-8 above.
                    // There is no need to filter UTF-8 BOM here, since ICU does not distinguish it from UTF-8.
                    if name != "UTF-8" {
                        ENCODINGS.push(EncodingInfo { name, aliases: get_aliases(c_name, f) })
                    }

                    n += 1;
                }
            }
        }

        &ENCODINGS
    }
}


Review comment (suggestion):
I think the name of this encoding is slightly "stringly-typed" and required by some other code:

https://github.com/microsoft/edit/blob/a82483d9ef1ec0bc3d9812a4ab96077c0c9cee01/src/buffer/mod.rs#L746-L750

Code after:
use std::ffi::CStr;
use std::mem;
use std::mem::MaybeUninit;
use std::ops::Range;
use std::ptr::{null, null_mut};

use crate::arena::{Arena, ArenaString, scratch_arena};
use crate::buffer::TextBuffer;
use crate::unicode::Utf8Chars;
use crate::{apperr, arena_format, sys};

#[derive(Clone, Copy)]
pub struct Encoding {
    pub label: &'static str,
    pub canonical: &'static str,
}

pub struct Encodings {
    pub preferred: &'static [Encoding],
    pub all: &'static [Encoding],
}

static mut ENCODINGS: Encodings = Encodings { preferred: &[], all: &[] };

/// Returns a list of encodings ICU supports.
pub fn get_available_encodings() -> &'static Encodings {
    // OnceCell for people that want to put it into a static.
    #[allow(static_mut_refs)]
    unsafe {
        if ENCODINGS.all.is_empty() {
            let scratch = scratch_arena(None);
            let mut preferred = Vec::new_in(&*scratch);
            let mut alternative = Vec::new_in(&*scratch);

            // These encodings are always available.
            preferred.push(Encoding { label: "UTF-8", canonical: "UTF-8" });
            preferred.push(Encoding { label: "UTF-8 BOM", canonical: "UTF-8 BOM" });

            if let Ok(f) = init_if_needed() {
                let mut n = 0;
                loop {
                    let name = (f.ucnv_getAvailableName)(n);
                    if name.is_null() {
                        break;
                    }

                    n += 1;

                    let name = CStr::from_ptr(name).to_str().unwrap_unchecked();
                    // We have already pushed UTF-8 above and can skip it.
                    // There is no need to filter UTF-8 BOM here,