Skip to content

Commit 17ce47c

Browse files
authored
Implement AsRef for Schema and Field (apache#8417)
# Which issue does this PR close? - closes apache#5819 # Rationale for this change This allows writing generic code that accepts `&Field`, `Arc<Field>` or `&Arc<Field>`, or iterators of these. Same for `Schema`. # What changes are included in this PR? `impl AsRef<Field> for Field` `impl AsRef<Schema> for Schema` as suggested by `AsRef` own docs # Are these changes tested? yes # Are there any user-facing changes? it does not break API. Downstream crates cannot implement `AsRef<Field> for Field` Downstream crates cannot workaround these either - apache#5819 (comment)
1 parent 0737c61 commit 17ce47c

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

arrow-schema/src/field.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,12 @@ impl Hash for Field {
172172
}
173173
}
174174

175+
impl AsRef<Field> for Field {
176+
fn as_ref(&self) -> &Field {
177+
self
178+
}
179+
}
180+
175181
impl Field {
176182
/// Default list member field name
177183
pub const LIST_FIELD_DEFAULT_NAME: &'static str = "item";
@@ -1259,6 +1265,36 @@ mod test {
12591265
assert!(f1.cmp(&f3).is_lt());
12601266
}
12611267

1268+
#[test]
1269+
#[expect(clippy::needless_borrows_for_generic_args)] // intentional to exercise various references
1270+
fn test_field_as_ref() {
1271+
let field = || Field::new("x", DataType::Binary, false);
1272+
1273+
// AsRef can be used in a function accepting a field.
1274+
// However, this case actually works a bit better when function takes `&Field`
1275+
fn accept_ref(_: impl AsRef<Field>) {}
1276+
1277+
accept_ref(field());
1278+
accept_ref(&field());
1279+
accept_ref(&&field());
1280+
accept_ref(Arc::new(field()));
1281+
accept_ref(&Arc::new(field()));
1282+
accept_ref(&&Arc::new(field()));
1283+
1284+
// AsRef can be used in a function accepting a collection of fields in any form,
1285+
// such as &[Field], or &[Arc<Field>]
1286+
fn accept_refs(_: impl IntoIterator<Item: AsRef<Field>>) {}
1287+
1288+
accept_refs(vec![field()]);
1289+
accept_refs(vec![&field()]);
1290+
accept_refs(vec![Arc::new(field())]);
1291+
accept_refs(vec![&Arc::new(field())]);
1292+
accept_refs(&vec![field()]);
1293+
accept_refs(&vec![&field()]);
1294+
accept_refs(&vec![Arc::new(field())]);
1295+
accept_refs(&vec![&Arc::new(field())]);
1296+
}
1297+
12621298
#[test]
12631299
fn test_contains_reflexivity() {
12641300
let mut field = Field::new("field1", DataType::Float16, false);

arrow-schema/src/schema.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,13 +546,38 @@ impl Hash for Schema {
546546
}
547547
}
548548

549+
impl AsRef<Schema> for Schema {
550+
fn as_ref(&self) -> &Schema {
551+
self
552+
}
553+
}
554+
549555
#[cfg(test)]
550556
mod tests {
551557
use crate::datatype::DataType;
552558
use crate::{TimeUnit, UnionMode};
553559

554560
use super::*;
555561

562+
#[test]
563+
#[expect(clippy::needless_borrows_for_generic_args)] // intentional to exercise various references
564+
fn test_schema_as_ref() {
565+
fn accept_ref(_: impl AsRef<Schema>) {}
566+
567+
let schema = Schema::new(vec![
568+
Field::new("name", DataType::Utf8, false),
569+
Field::new("address", DataType::Utf8, false),
570+
Field::new("priority", DataType::UInt8, false),
571+
]);
572+
573+
accept_ref(schema.clone());
574+
accept_ref(&schema.clone());
575+
accept_ref(&&schema.clone());
576+
accept_ref(Arc::new(schema.clone()));
577+
accept_ref(&Arc::new(schema.clone()));
578+
accept_ref(&&Arc::new(schema.clone()));
579+
}
580+
556581
#[test]
557582
#[cfg(feature = "serde")]
558583
fn test_ser_de_metadata() {

0 commit comments

Comments
 (0)