Files
uv/crates/uv-normalize/src/small_string.rs
T
Charlie Marsh b3d7beb1a0 Use arcstr for package, extra, and group names (#10475)
## Summary

This appears to be a consistent 1% performance improvement and should
also reduce memory quite a bit. We've also decided to use these for
markers, so it's nice to use the same optimization here.

```
❯ hyperfine "./uv pip compile --universal scripts/requirements/airflow.in" "./arcstr pip compile --universal scripts/requirements/airflow.in" --min-runs 50 --warmup 20
Benchmark 1: ./uv pip compile --universal scripts/requirements/airflow.in
  Time (mean ± σ):     136.3 ms ±   4.0 ms    [User: 139.1 ms, System: 241.9 ms]
  Range (min … max):   131.5 ms … 149.5 ms    50 runs

Benchmark 2: ./arcstr pip compile --universal scripts/requirements/airflow.in
  Time (mean ± σ):     134.9 ms ±   3.2 ms    [User: 137.6 ms, System: 239.0 ms]
  Range (min … max):   130.1 ms … 151.8 ms    50 runs

Summary
  ./arcstr pip compile --universal scripts/requirements/airflow.in ran
    1.01 ± 0.04 times faster than ./uv pip compile --universal scripts/requirements/airflow.in
```
2025-01-10 19:46:36 +00:00

120 lines
3.0 KiB
Rust

use std::cmp::PartialEq;
use std::ops::Deref;
/// An optimized small string type for short identifiers, like package names.
///
/// Represented as an [`arcstr::ArcStr`] internally.
#[derive(Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct SmallString(arcstr::ArcStr);
impl From<&str> for SmallString {
#[inline]
fn from(s: &str) -> Self {
Self(s.into())
}
}
impl From<String> for SmallString {
#[inline]
fn from(s: String) -> Self {
Self(s.into())
}
}
impl AsRef<str> for SmallString {
#[inline]
fn as_ref(&self) -> &str {
&self.0
}
}
impl Deref for SmallString {
type Target = str;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl core::fmt::Debug for SmallString {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(&self.0, f)
}
}
impl core::fmt::Display for SmallString {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Display::fmt(&self.0, f)
}
}
/// A [`serde::Serialize`] implementation for [`SmallString`].
impl serde::Serialize for SmallString {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.0.serialize(serializer)
}
}
/// An [`rkyv`] implementation for [`SmallString`].
impl rkyv::Archive for SmallString {
type Archived = rkyv::string::ArchivedString;
type Resolver = rkyv::string::StringResolver;
#[inline]
fn resolve(&self, resolver: Self::Resolver, out: rkyv::Place<Self::Archived>) {
rkyv::string::ArchivedString::resolve_from_str(&self.0, resolver, out);
}
}
impl<S> rkyv::Serialize<S> for SmallString
where
S: rkyv::rancor::Fallible + rkyv::ser::Allocator + rkyv::ser::Writer + ?Sized,
S::Error: rkyv::rancor::Source,
{
fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
rkyv::string::ArchivedString::serialize_from_str(&self.0, serializer)
}
}
impl<D: rkyv::rancor::Fallible + ?Sized> rkyv::Deserialize<SmallString, D>
for rkyv::string::ArchivedString
{
fn deserialize(&self, _deserializer: &mut D) -> Result<SmallString, D::Error> {
Ok(SmallString::from(self.as_str()))
}
}
impl PartialEq<SmallString> for rkyv::string::ArchivedString {
fn eq(&self, other: &SmallString) -> bool {
**other == **self
}
}
impl PartialOrd<SmallString> for rkyv::string::ArchivedString {
fn partial_cmp(&self, other: &SmallString) -> Option<::core::cmp::Ordering> {
Some(self.as_str().cmp(other))
}
}
/// An [`schemars::JsonSchema`] implementation for [`SmallString`].
#[cfg(feature = "schemars")]
impl schemars::JsonSchema for SmallString {
fn is_referenceable() -> bool {
String::is_referenceable()
}
fn schema_name() -> String {
String::schema_name()
}
fn json_schema(_gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
String::json_schema(_gen)
}
}