Skip to content

Commit

Permalink
Use triomphe::Arc to mitigate performance losses
Browse files Browse the repository at this point in the history
This change replaces `std::sync::Arc` with `triomphe::Arc`. The latter
has no weak references, and is a lot faster because of that.
  • Loading branch information
Kijewski committed Jan 19, 2024
1 parent b740582 commit eba3abb
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 36 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ You can use `rust_i18n::set_locale` to set the global locale at runtime, so that
rust_i18n::set_locale("zh-CN");
let locale = rust_i18n::locale();
assert_eq!(*locale, "zh-CN");
assert_eq!(&*locale, "zh-CN");
```

### Extend Backend
Expand Down
1 change: 1 addition & 0 deletions crates/support/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ toml = "0.7.4"
normpath = "1.1.1"
lazy_static = "1"
regex = "1"
triomphe = { version = "0.1.11", features = ["arc-swap"] }
45 changes: 14 additions & 31 deletions crates/support/src/atomic_str.rs
Original file line number Diff line number Diff line change
@@ -1,67 +1,50 @@
use std::fmt;
use std::sync::Arc;
use std::ops::Deref;

use arc_swap::{ArcSwap, Guard};
use arc_swap::{ArcSwapAny, Guard};
use triomphe::Arc;

/// A thread-safe atomically reference-counting string.
pub struct AtomicStr(ArcSwap<String>);
pub struct AtomicStr(ArcSwapAny<Arc<String>>);

/// A thread-safe view the string that was stored when `AtomicStr::as_str()` was called.
struct GuardedStr(Guard<Arc<String>>);

impl AsRef<str> for GuardedStr {
fn as_ref(&self) -> &str {
self.0.as_str()
}
}
impl Deref for GuardedStr {
type Target = str;

impl fmt::Display for GuardedStr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.0.as_ref())
fn deref(&self) -> &Self::Target {
self.0.as_str()
}
}

impl AtomicStr {
/// Create a new `AtomicStr` with the given value.
pub fn new(value: impl Into<String>) -> Self {
pub fn new(value: &str) -> Self {
let arced = Arc::new(value.into());
Self(ArcSwap::new(arced))
Self(ArcSwapAny::new(arced))
}

/// Get the string slice.
pub fn as_str(&self) -> impl AsRef<str> + fmt::Display {
pub fn as_str(&self) -> impl Deref<Target = str> {
GuardedStr(self.0.load())
}

/// Get the cloned inner `Arc<String>`.
pub fn clone_string(&self) -> Arc<String> {
Guard::into_inner(self.0.load())
}

/// Replaces the value at self with src.
pub fn replace(&self, src: impl Into<String>) {
let arced = Arc::new(src.into());
self.0.store(arced);
}
}

impl<T> From<T> for AtomicStr
where
T: Into<String>,
{
fn from(value: T) -> Self {
impl From<&str> for AtomicStr {
fn from(value: &str) -> Self {
Self::new(value)
}
}

impl From<&AtomicStr> for Arc<String> {
fn from(value: &AtomicStr) -> Self {
value.clone_string()
}
}

impl fmt::Display for AtomicStr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
f.write_str(&self.as_str())
}
}
9 changes: 5 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#![doc = include_str!("../README.md")]

use std::ops::Deref;

use once_cell::sync::Lazy;
use std::sync::Arc;

#[doc(hidden)]
pub use once_cell;
Expand All @@ -16,8 +17,8 @@ pub fn set_locale(locale: &str) {
}

/// Get current locale
pub fn locale() -> Arc<String> {
CURRENT_LOCALE.clone_string()
pub fn locale() -> impl Deref<Target = str> {
CURRENT_LOCALE.as_str()
}

/// Replace patterns and return a new string.
Expand Down Expand Up @@ -110,7 +111,7 @@ pub fn replace_patterns(input: &str, patterns: &[&str], values: &[String]) -> St
macro_rules! t {
// t!("foo")
($key:expr) => {
crate::_rust_i18n_translate(rust_i18n::locale().as_str(), $key)
crate::_rust_i18n_translate(&rust_i18n::locale(), $key)
};

// t!("foo", locale = "en")
Expand Down

0 comments on commit eba3abb

Please sign in to comment.