Skip to content

Commit 08f3241

Browse files
goffrieConvex, Inc.
authored andcommitted
Avoid creating and throwing away anyhow::Errors in ObjectShape::shape_of (#41729)
anyhow::Error takes a backtrace on construction which is quite expensive. GitOrigin-RevId: b26c197980df29c1466b8ce3ef9ad89350590a73
1 parent 2747d6b commit 08f3241

File tree

2 files changed

+38
-28
lines changed

2 files changed

+38
-28
lines changed

crates/convex/sync_types/src/identifier.rs

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use std::{
2-
fmt::Display,
2+
fmt::{
3+
self,
4+
Display,
5+
},
36
ops::Deref,
47
str::FromStr,
58
};
@@ -28,11 +31,11 @@ pub const IDENTIFIER_REQUIREMENTS: &str =
2831
/// [^3]: <https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=%5B%3AXID_START%3A%5D&g=&i=>
2932
/// [^4]: <https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=%5B%3AXID_CONTINUE%3A%5D&g=&i=>
3033
pub fn check_valid_identifier(s: &str) -> anyhow::Result<()> {
31-
check_valid_identifier_inner(s).map_err(|e| anyhow::anyhow!(e))
34+
check_valid_identifier_inner(s, |e| anyhow::anyhow!(e.to_string()))
3235
}
3336

3437
pub fn is_valid_identifier(s: &str) -> bool {
35-
check_valid_identifier_inner(s).is_ok()
38+
check_valid_identifier_inner(s, |_| ()).is_ok()
3639
}
3740

3841
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
@@ -77,38 +80,41 @@ impl Deref for Identifier {
7780
}
7881
}
7982

80-
fn check_valid_identifier_inner(s: &str) -> Result<(), String> {
83+
fn check_valid_identifier_inner<E>(
84+
s: &str,
85+
error: impl FnOnce(fmt::Arguments<'_>) -> E,
86+
) -> Result<(), E> {
8187
let mut chars = s.chars();
8288
match chars.next() {
8389
Some(c) if c.is_ascii_alphabetic() => (),
8490
Some('_') => (),
8591
Some(c) => {
86-
return Err(format!(
92+
return Err(error(format_args!(
8793
"Invalid first character '{c}' in {s}: Identifiers must start with an alphabetic \
8894
character or underscore"
89-
))
95+
)))
9096
},
91-
None => return Err(format!("Identifier cannot be empty")),
97+
None => return Err(error(format_args!("Identifier cannot be empty"))),
9298
};
9399
for c in chars {
94100
if !c.is_ascii_alphanumeric() && c != '_' {
95-
return Err(format!(
101+
return Err(error(format_args!(
96102
"Identifier {s} has invalid character '{c}': Identifiers can only contain \
97103
alphanumeric characters or underscores"
98-
));
104+
)));
99105
}
100106
}
101107
if s.len() > MAX_IDENTIFIER_LEN {
102-
return Err(format!(
108+
return Err(error(format_args!(
103109
"Identifier is too long ({} > maximum {})",
104110
s.len(),
105111
MAX_IDENTIFIER_LEN
106-
));
112+
)));
107113
}
108114
if s.chars().all(|c| c == '_') {
109-
return Err(format!(
115+
return Err(error(format_args!(
110116
"Identifier {s} cannot have exclusively underscores"
111-
));
117+
)));
112118
}
113119
Ok(())
114120
}

crates/shape_inference/src/object.rs

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::{
44
};
55

66
use value::{
7+
identifier::is_valid_identifier,
78
ConvexObject,
89
IdentifierFieldName,
910
};
@@ -75,22 +76,25 @@ impl<C: ShapeConfig> ObjectShape<C, u64> {
7576
}
7677

7778
pub fn shape_of(object: &ConvexObject) -> CountedShapeEnum<C> {
78-
if object.len() <= C::MAX_OBJECT_FIELDS {
79-
if let Ok(fields) = object
79+
// N.B.: check is_valid_identifier separately to avoid creating
80+
// anyhow::Errors, which is expensive
81+
if object.len() <= C::MAX_OBJECT_FIELDS
82+
&& object.iter().all(|(f, _)| is_valid_identifier(f))
83+
{
84+
let field_shapes: BTreeMap<_, _> = object
8085
.iter()
81-
.map(|(f, v)| Ok((IdentifierFieldName::try_from(f.clone())?, v)))
82-
.collect::<anyhow::Result<BTreeMap<_, _>>>()
83-
{
84-
let mut field_shapes = BTreeMap::new();
85-
for (field_name, value) in fields {
86-
let field = ObjectField {
87-
value_shape: Shape::shape_of(value),
88-
optional: false,
89-
};
90-
field_shapes.insert(field_name.clone(), field);
91-
}
92-
return ShapeEnum::Object(Self::new(field_shapes));
93-
}
86+
.map(|(field_name, value)| {
87+
(
88+
IdentifierFieldName::try_from(field_name.clone())
89+
.expect("checked is_valid_identifier above"),
90+
ObjectField {
91+
value_shape: Shape::shape_of(value),
92+
optional: false,
93+
},
94+
)
95+
})
96+
.collect();
97+
return ShapeEnum::Object(Self::new(field_shapes));
9498
}
9599
let mut fields = UnionBuilder::new();
96100
let mut values = UnionBuilder::new();

0 commit comments

Comments
 (0)