Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

75
vendor/sys-locale/src/android.rs vendored Normal file
View File

@@ -0,0 +1,75 @@
use alloc::{string::String, vec};
use core::convert::TryFrom;
fn get_property(name: &'static [u8]) -> Option<String> {
let mut value = vec![0u8; libc::PROP_VALUE_MAX as usize];
// SAFETY: `name` is valid to read from and `value` is valid to write to.
let len =
unsafe { libc::__system_property_get(name.as_ptr().cast(), value.as_mut_ptr().cast()) };
usize::try_from(len)
.ok()
.filter(|n| *n != 0)
.and_then(move |n| {
// Remove excess bytes and the NUL terminator
value.resize(n, 0);
String::from_utf8(value).ok()
})
}
const LOCALE_KEY: &[u8] = b"persist.sys.locale\0";
const PRODUCT_LOCALE_KEY: &[u8] = b"ro.product.locale\0";
const PRODUCT_LANGUAGE_KEY: &[u8] = b"ro.product.locale.language\0";
const PRODUCT_REGION_KEY: &[u8] = b"ro.product.locale.region\0";
// Android 4.0 and below
const LANG_KEY: &[u8] = b"persist.sys.language\0";
const COUNTRY_KEY: &[u8] = b"persist.sys.country\0";
const LOCALEVAR_KEY: &[u8] = b"persist.sys.localevar\0";
// Ported from https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/jni/AndroidRuntime.cpp#431
fn read_locale() -> Option<String> {
if let Some(locale) = get_property(LOCALE_KEY) {
return Some(locale);
}
// Android 4.0 and below
if let Some(mut language) = get_property(LANG_KEY) {
// The details of this functionality are not publically available, so this is just
// adapted "best effort" from the original code.
match get_property(COUNTRY_KEY) {
Some(country) => {
language.push('-');
language.push_str(&country);
}
None => {
if let Some(variant) = get_property(LOCALEVAR_KEY) {
language.push('-');
language.push_str(&variant);
}
}
};
return Some(language);
}
if let Some(locale) = get_property(PRODUCT_LOCALE_KEY) {
return Some(locale);
}
let product_language = get_property(PRODUCT_LANGUAGE_KEY);
let product_region = get_property(PRODUCT_REGION_KEY);
match (product_language, product_region) {
(Some(mut lang), Some(region)) => {
lang.push('-');
lang.push_str(&region);
Some(lang)
}
_ => None,
}
}
pub(crate) fn get() -> impl Iterator<Item = String> {
read_locale().into_iter()
}

166
vendor/sys-locale/src/apple.rs vendored Normal file
View File

@@ -0,0 +1,166 @@
use alloc::{string::String, vec::Vec};
use core::ffi::c_void;
type CFIndex = isize;
type Boolean = u8;
type CFStringEncoding = u32;
#[allow(non_upper_case_globals)]
const kCFStringEncodingUTF8: CFStringEncoding = 0x08000100;
#[repr(C)]
#[derive(Clone, Copy)]
struct CFRange {
pub location: CFIndex,
pub length: CFIndex,
}
type CFTypeRef = *const c_void;
#[repr(C)]
struct __CFArray(c_void);
type CFArrayRef = *const __CFArray;
#[repr(C)]
struct __CFString(c_void);
type CFStringRef = *const __CFString;
// Most of these definitions come from `core-foundation-sys`, but we want this crate
// to be `no_std` and `core-foundation-sys` isn't currently.
#[link(name = "CoreFoundation", kind = "framework")]
extern "C" {
fn CFArrayGetCount(theArray: CFArrayRef) -> CFIndex;
fn CFArrayGetValueAtIndex(theArray: CFArrayRef, idx: CFIndex) -> *const c_void;
fn CFStringGetLength(theString: CFStringRef) -> CFIndex;
fn CFStringGetBytes(
theString: CFStringRef,
range: CFRange,
encoding: CFStringEncoding,
lossByte: u8,
isExternalRepresentation: Boolean,
buffer: *mut u8,
maxBufLen: CFIndex,
usedBufLen: *mut CFIndex,
) -> CFIndex;
fn CFRelease(cf: CFTypeRef);
fn CFLocaleCopyPreferredLanguages() -> CFArrayRef;
}
pub(crate) fn get() -> impl Iterator<Item = String> {
let preferred_langs = get_languages();
let mut idx = 0;
#[allow(clippy::as_conversions)]
core::iter::from_fn(move || unsafe {
let (langs, num_langs) = preferred_langs.as_ref()?;
// 0 to N-1 inclusive
if idx >= *num_langs {
return None;
}
// SAFETY: The current index has been checked that its still within bounds of the array.
// XXX: We don't retain the strings because we know we have total ownership of the backing array.
let locale = CFArrayGetValueAtIndex(langs.0, idx) as CFStringRef;
idx += 1;
// SAFETY: `locale` is a valid CFString pointer because the array will always contain a value.
let str_len = CFStringGetLength(locale);
let range = CFRange {
location: 0,
length: str_len,
};
let mut capacity = 0;
// SAFETY:
// - `locale` is a valid CFString
// - The supplied range is within the length of the string.
// - `capacity` is writable.
// Passing NULL and `0` is correct for the buffer to get the
// encoded output length.
CFStringGetBytes(
locale,
range,
kCFStringEncodingUTF8,
0,
false as Boolean,
core::ptr::null_mut(),
0,
&mut capacity,
);
// Guard against a zero-sized allocation, if that were to somehow occur.
if capacity == 0 {
return None;
}
// Note: This is the number of bytes (u8) that will be written to
// the buffer, not the number of codepoints they would contain.
let mut buffer = Vec::with_capacity(capacity as usize);
// SAFETY:
// - `locale` is a valid CFString
// - The supplied range is within the length of the string.
// - `buffer` is writable and has sufficent capacity to receive the data.
// - `maxBufLen` is correctly based on `buffer`'s available capacity.
// - `out_len` is writable.
let mut out_len = 0;
CFStringGetBytes(
locale,
range,
kCFStringEncodingUTF8,
0,
false as Boolean,
buffer.as_mut_ptr(),
capacity as CFIndex,
&mut out_len,
);
// Sanity check that both calls to `CFStringGetBytes`
// were equivalent. If they weren't, the system is doing
// something very wrong...
assert!(out_len <= capacity);
// SAFETY: The system has written `out_len` elements, so they are
// initialized and inside the buffer's capacity bounds.
buffer.set_len(out_len as usize);
// This should always contain UTF-8 since we told the system to
// write UTF-8 into the buffer, but the value is small enough that
// using `from_utf8_unchecked` isn't worthwhile.
String::from_utf8(buffer).ok()
})
}
fn get_languages() -> Option<(CFArray, CFIndex)> {
unsafe {
// SAFETY: This function is safe to call and has no invariants. Any value inside the
// array will be owned by us.
let langs = CFLocaleCopyPreferredLanguages();
if !langs.is_null() {
let langs = CFArray(langs);
// SAFETY: The returned array is a valid CFArray object.
let count = CFArrayGetCount(langs.0);
if count != 0 {
Some((langs, count))
} else {
None
}
} else {
None
}
}
}
struct CFArray(CFArrayRef);
impl Drop for CFArray {
fn drop(&mut self) {
// SAFETY: This wrapper contains a valid CFArray.
unsafe { CFRelease(self.0.cast()) }
}
}

112
vendor/sys-locale/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,112 @@
//! A library to safely and easily obtain the current locale on the system or for an application.
//!
//! This library currently supports the following platforms:
//! - Android
//! - iOS (and derivatives such as watchOS, tvOS, and visionOS)
//! - macOS
//! - Linux, BSD, and other UNIX variations
//! - WebAssembly on the web (via the `js` feature)
//! - Windows
#![cfg_attr(any(not(unix), target_vendor = "apple", target_os = "android"), no_std)]
extern crate alloc;
use alloc::string::String;
#[cfg(target_os = "android")]
mod android;
#[cfg(target_os = "android")]
use android as provider;
#[cfg(target_vendor = "apple")]
mod apple;
#[cfg(target_vendor = "apple")]
use apple as provider;
#[cfg(all(unix, not(any(target_vendor = "apple", target_os = "android"))))]
mod unix;
#[cfg(all(unix, not(any(target_vendor = "apple", target_os = "android"))))]
use unix as provider;
#[cfg(all(target_family = "wasm", feature = "js", not(unix)))]
mod wasm;
#[cfg(all(target_family = "wasm", feature = "js", not(unix)))]
use wasm as provider;
#[cfg(windows)]
mod windows;
#[cfg(windows)]
use windows as provider;
#[cfg(not(any(unix, all(target_family = "wasm", feature = "js", not(unix)), windows)))]
mod provider {
pub fn get() -> impl Iterator<Item = alloc::string::String> {
core::iter::empty()
}
}
/// Returns the most preferred locale for the system or application.
///
/// This is equivalent to `get_locales().next()` (the first entry).
///
/// # Returns
///
/// Returns [`Some(String)`] with a BCP 47 language tag inside.
/// If the locale couldn't be obtained, [`None`] is returned instead.
///
/// # Example
///
/// ```no_run
/// use sys_locale::get_locale;
///
/// let current_locale = get_locale().unwrap_or_else(|| String::from("en-US"));
///
/// println!("The locale is {}", current_locale);
/// ```
pub fn get_locale() -> Option<String> {
get_locales().next()
}
/// Returns the preferred locales for the system or application, in descending order of preference.
///
/// # Returns
///
/// Returns an [`Iterator`] with any number of BCP 47 language tags inside.
/// If no locale preferences could be obtained, the iterator will be empty.
///
/// # Example
///
/// ```no_run
/// use sys_locale::get_locales;
///
/// let mut locales = get_locales();
///
/// println!("The most preferred locale is {}", locales.next().unwrap_or("en-US".to_string()));
/// println!("The least preferred locale is {}", locales.last().unwrap_or("en-US".to_string()));
/// ```
pub fn get_locales() -> impl Iterator<Item = String> {
provider::get()
}
#[cfg(test)]
mod tests {
use super::{get_locale, get_locales};
extern crate std;
#[cfg(all(target_family = "wasm", feature = "js", not(unix)))]
use wasm_bindgen_test::wasm_bindgen_test as test;
#[cfg(all(target_family = "wasm", feature = "js", not(unix)))]
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
#[test]
fn can_obtain_locale() {
assert!(get_locale().is_some(), "no locales were returned");
let locales = get_locales();
for (i, locale) in locales.enumerate() {
assert!(!locale.is_empty(), "locale string {} was empty", i);
assert!(
!locale.ends_with('\0'),
"locale {} contained trailing NUL",
i
);
}
}
}

296
vendor/sys-locale/src/unix.rs vendored Normal file
View File

@@ -0,0 +1,296 @@
use std::{env, ffi::OsStr};
const LANGUAGE: &str = "LANGUAGE";
const LC_ALL: &str = "LC_ALL";
const LC_MESSAGES: &str = "LC_MESSAGES";
const LANG: &str = "LANG";
/// Environment variable access abstraction to allow testing without
/// mutating env variables.
///
/// Use [StdEnv] to query [std::env]
trait EnvAccess {
/// See also [std::env::var]
fn get(&self, key: impl AsRef<OsStr>) -> Option<String>;
}
/// Proxy to [std::env]
struct StdEnv;
impl EnvAccess for StdEnv {
fn get(&self, key: impl AsRef<OsStr>) -> Option<String> {
env::var(key).ok()
}
}
pub(crate) fn get() -> impl Iterator<Item = String> {
_get(&StdEnv)
}
/// Retrieves a list of unique locales by checking specific environment variables
/// in a predefined order: LANGUAGE, LC_ALL, LC_MESSAGES, and LANG.
///
/// The function first checks the `LANGUAGE` environment variable, which can contain
/// one or more locales separated by a colon (`:`). It then splits these values,
/// converts them from [POSIX](https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap08.html)
/// to [BCP 47](https://www.ietf.org/rfc/bcp/bcp47.html) format, and adds them to the list of locales
/// if they are not already included.
///
/// Next, the function checks the `LC_ALL`, `LC_MESSAGES`, and `LANG` environment
/// variables. Each of these variables contains a single locale. If a locale is found,
/// and it's not empty, it is converted to BCP 47 format and added to the list if
/// it is not already included.
///
/// For more information check this issue: https://github.com/1Password/sys-locale/issues/14.
///
/// The function ensures that locales are returned in the order of precedence
/// and without duplicates. The final list of locales is returned as an iterator.
///
/// # Returns
///
/// An iterator over the unique locales found in the environment variables.
///
/// # Environment Variables Checked
///
/// 1. `LANGUAGE` - Can contain multiple locales, each separated by a colon (`:`), highest priority.
/// 2. `LC_ALL` - Contains a single locale, high priority.
/// 3. `LC_MESSAGES` - Contains a single locale, medium priority.
/// 4. `LANG` - Contains a single locale, low priority.
///
/// # Example
///
/// ```ignore
/// let locales: Vec<String> = _get(&env).collect();
/// for locale in locales {
/// println!("User's preferred locales: {}", locale);
/// }
/// ```
fn _get(env: &impl EnvAccess) -> impl Iterator<Item = String> {
let mut locales = Vec::new();
// LANGUAGE contains one or multiple locales separated by colon (':')
if let Some(val) = env.get(LANGUAGE).filter(|val| !val.is_empty()) {
for part in val.split(':') {
let locale = posix_to_bcp47(part);
if !locales.contains(&locale) {
locales.push(locale);
}
}
}
// LC_ALL, LC_MESSAGES and LANG contain one locale
for variable in [LC_ALL, LC_MESSAGES, LANG] {
if let Some(val) = env.get(variable).filter(|val| !val.is_empty()) {
let locale = posix_to_bcp47(&val);
if !locales.contains(&locale) {
locales.push(locale);
}
}
}
locales.into_iter()
}
/// Converts a POSIX locale string to a BCP 47 locale string.
///
/// This function processes the input `code` by removing any character encoding
/// (the part after the `.` character) and any modifiers (the part after the `@` character).
/// It replaces underscores (`_`) with hyphens (`-`) to conform to BCP 47 formatting.
///
/// If the locale is already in the BCP 47 format, no changes are made.
///
/// Useful links:
/// - [The Open Group Base Specifications Issue 8 - 7. Locale](https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap07.html)
/// - [The Open Group Base Specifications Issue 8 - 8. Environment Variables](https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap08.html)
/// - [BCP 47 specification](https://www.ietf.org/rfc/bcp/bcp47.html)
///
/// # Examples
///
/// ```ignore
/// let bcp47 = posix_to_bcp47("en-US"); // already BCP 47
/// assert_eq!(bcp47, "en-US"); // no changes
///
/// let bcp47 = posix_to_bcp47("en_US");
/// assert_eq!(bcp47, "en-US");
///
/// let bcp47 = posix_to_bcp47("ru_RU.UTF-8");
/// assert_eq!(bcp47, "ru-RU");
///
/// let bcp47 = posix_to_bcp47("fr_FR@dict");
/// assert_eq!(bcp47, "fr-FR");
///
/// let bcp47 = posix_to_bcp47("de_DE.UTF-8@euro");
/// assert_eq!(bcp47, "de-DE");
/// ```
///
/// # TODO
///
/// 1. Implement POSIX to BCP 47 modifier conversion (see https://github.com/1Password/sys-locale/issues/32).
/// 2. Optimize to avoid creating a new buffer (see https://github.com/1Password/sys-locale/pull/33).
fn posix_to_bcp47(locale: &str) -> String {
locale
.chars()
.take_while(|&c| c != '.' && c != '@')
.map(|c| if c == '_' { '-' } else { c })
.collect()
}
#[cfg(test)]
mod tests {
use super::{EnvAccess, _get, posix_to_bcp47, LANG, LANGUAGE, LC_ALL, LC_MESSAGES};
use std::{
collections::HashMap,
ffi::{OsStr, OsString},
};
type MockEnv = HashMap<OsString, String>;
impl EnvAccess for MockEnv {
fn get(&self, key: impl AsRef<OsStr>) -> Option<String> {
self.get(key.as_ref()).cloned()
}
}
const BCP_47: &str = "fr-FR";
const POSIX: &str = "fr_FR";
const POSIX_ENC: &str = "fr_FR.UTF-8";
const POSIX_MOD: &str = "fr_FR@euro";
const POSIX_ENC_MOD: &str = "fr_FR.UTF-8@euro";
#[test]
fn parse_identifier() {
assert_eq!(posix_to_bcp47(BCP_47), BCP_47);
assert_eq!(posix_to_bcp47(POSIX), BCP_47);
assert_eq!(posix_to_bcp47(POSIX_ENC), BCP_47);
assert_eq!(posix_to_bcp47(POSIX_MOD), BCP_47);
assert_eq!(posix_to_bcp47(POSIX_ENC_MOD), BCP_47);
}
#[test]
fn env_get() {
fn case(
env: &mut MockEnv,
language: impl Into<String>,
lc_all: impl Into<String>,
lc_messages: impl Into<String>,
lang: impl Into<String>,
expected: impl IntoIterator<Item = impl Into<String>>,
) {
env.insert(LANGUAGE.into(), language.into());
env.insert(LC_ALL.into(), lc_all.into());
env.insert(LC_MESSAGES.into(), lc_messages.into());
env.insert(LANG.into(), lang.into());
assert!(_get(env).eq(expected.into_iter().map(|s| s.into())));
}
let mut env = MockEnv::new();
assert_eq!(_get(&env).next(), None);
// Empty
case(&mut env, "", "", "", "", &[] as &[String]);
// Constants
case(
&mut env,
POSIX_ENC_MOD,
POSIX_ENC,
POSIX_MOD,
POSIX,
[BCP_47],
);
// Only one variable
case(&mut env, "en_US", "", "", "", ["en-US"]);
case(&mut env, "", "en_US", "", "", ["en-US"]);
case(&mut env, "", "", "en_US", "", ["en-US"]);
case(&mut env, "", "", "", "en_US", ["en-US"]);
// Duplicates
case(&mut env, "en_US", "en_US", "en_US", "en_US", ["en-US"]);
case(
&mut env,
"en_US",
"en_US",
"ru_RU",
"en_US",
["en-US", "ru-RU"],
);
case(
&mut env,
"en_US",
"ru_RU",
"ru_RU",
"en_US",
["en-US", "ru-RU"],
);
case(
&mut env,
"en_US",
"es_ES",
"ru_RU",
"en_US",
["en-US", "es-ES", "ru-RU"],
);
case(
&mut env,
"en_US:ru_RU:es_ES:en_US",
"es_ES",
"ru_RU",
"en_US",
["en-US", "ru-RU", "es-ES"],
);
// Duplicates with different case
case(
&mut env,
"en_US:fr_fr",
"EN_US",
"fR_Fr",
"En_US",
["en-US", "fr-fr", "EN-US", "fR-Fr", "En-US"],
);
// More complicated cases
case(
&mut env,
"ru_RU:ru:en_US:en",
"ru_RU.UTF-8",
"ru_RU.UTF-8",
"ru_RU.UTF-8",
["ru-RU", "ru", "en-US", "en"],
);
case(
&mut env,
"fr_FR.UTF-8@euro:fr_FR.UTF-8:fr_FR:fr:en_US.UTF-8:en_US:en",
"es_ES.UTF-8@euro",
"fr_FR.UTF-8@euro",
"fr_FR.UTF-8@euro",
["fr-FR", "fr", "en-US", "en", "es-ES"],
);
case(
&mut env,
"",
"es_ES.UTF-8@euro",
"fr_FR.UTF-8@euro",
"fr_FR.UTF-8@euro",
["es-ES", "fr-FR"],
);
case(
&mut env,
"fr_FR@euro",
"fr_FR.UTF-8",
"en_US.UTF-8",
"en_US.UTF-8@dict",
["fr-FR", "en-US"],
);
// Already BCP 47
case(&mut env, BCP_47, BCP_47, BCP_47, POSIX, [BCP_47]);
case(
&mut env,
"fr-FR",
"es-ES",
"de-DE",
"en-US",
["fr-FR", "es-ES", "de-DE", "en-US"],
);
}
}

56
vendor/sys-locale/src/wasm.rs vendored Normal file
View File

@@ -0,0 +1,56 @@
use alloc::string::String;
use js_sys::{JsString, Object};
use wasm_bindgen::{prelude::*, JsCast, JsValue};
#[derive(Clone)]
enum GlobalType {
Window(web_sys::Window),
Worker(web_sys::WorkerGlobalScope),
}
/// Returns a handle to the global scope object.
///
/// Simplified version of https://github.com/rustwasm/wasm-bindgen/blob/main/crates/js-sys/src/lib.rs,
/// which we can't use directly because it discards information about how it
/// retrieved the global.
fn global() -> GlobalType {
#[wasm_bindgen]
extern "C" {
type Global;
#[wasm_bindgen(getter, catch, static_method_of = Global, js_class = window, js_name = window)]
fn get_window() -> Result<Object, JsValue>;
#[wasm_bindgen(getter, catch, static_method_of = Global, js_class = self, js_name = self)]
fn get_self() -> Result<Object, JsValue>;
}
if let Ok(window) = Global::get_window() {
GlobalType::Window(
window
.dyn_into::<web_sys::Window>()
.expect("expected window to be an instance of Window"),
)
} else if let Ok(worker) = Global::get_self() {
GlobalType::Worker(
worker
.dyn_into::<web_sys::WorkerGlobalScope>()
.expect("expected self to be an instance of WorkerGlobalScope"),
)
} else {
panic!("Unable to find global in this environment")
}
}
pub(crate) fn get() -> impl Iterator<Item = String> {
let languages = match global() {
GlobalType::Window(window) => window.navigator().languages(),
GlobalType::Worker(worker) => worker.navigator().languages(),
};
languages
.values()
.into_iter()
.flat_map(|v| v.and_then(|v| v.dyn_into::<JsString>()))
.map(String::from)
}

50
vendor/sys-locale/src/windows.rs vendored Normal file
View File

@@ -0,0 +1,50 @@
use alloc::{string::String, vec::Vec};
#[path = "./windows_sys.rs"]
mod windows_sys;
use windows_sys::{GetUserPreferredUILanguages, MUI_LANGUAGE_NAME, TRUE};
#[allow(clippy::as_conversions)]
pub(crate) fn get() -> impl Iterator<Item = String> {
let mut num_languages: u32 = 0;
let mut buffer_length: u32 = 0;
// Calling this with null buffer will retrieve the required buffer length
let success = unsafe {
GetUserPreferredUILanguages(
MUI_LANGUAGE_NAME,
&mut num_languages,
core::ptr::null_mut(),
&mut buffer_length,
)
} == TRUE;
if !success {
return Vec::new().into_iter();
}
let mut buffer = Vec::<u16>::with_capacity(buffer_length as usize);
// Now that we have an appropriate buffer, we can query the names
let mut result = Vec::with_capacity(num_languages as usize);
let success = unsafe {
GetUserPreferredUILanguages(
MUI_LANGUAGE_NAME,
&mut num_languages,
buffer.as_mut_ptr(),
&mut buffer_length,
)
} == TRUE;
if success {
// SAFETY: Windows wrote the required length worth of UTF-16 into our buffer, which initialized it.
unsafe { buffer.set_len(buffer_length as usize) };
// The buffer contains names split by null char (0), and ends with two null chars (00)
for part in buffer.split(|i| *i == 0).filter(|p| !p.is_empty()) {
if let Ok(locale) = String::from_utf16(part) {
result.push(locale);
}
}
}
result.into_iter()
}

22
vendor/sys-locale/src/windows_sys.rs vendored Normal file
View File

@@ -0,0 +1,22 @@
// Bindings generated by `windows-bindgen` 0.51.1
#![allow(
non_snake_case,
non_upper_case_globals,
non_camel_case_types,
dead_code,
clippy::all
)]
#[link(name = "kernel32")]
extern "system" {
pub fn GetUserPreferredUILanguages(
dwflags: u32,
pulnumlanguages: *mut u32,
pwszlanguagesbuffer: PWSTR,
pcchlanguagesbuffer: *mut u32,
) -> BOOL;
}
pub type BOOL = i32;
pub const MUI_LANGUAGE_NAME: u32 = 8u32;
pub type PWSTR = *mut u16;
pub const TRUE: BOOL = 1i32;