1- /// A trait to safely index into a structure with an `Accessor`.
2- /// This will never panic and return an `Option::None` on failure.
3- pub trait SafelyIndex < X = Self > {
4- /// Attempt to access a field
5- fn get ( & self , key : impl Into < Accessor > ) -> Option < & X > ;
1+ /// A trait to index without panicking into a structure through an [`Accessor`].
2+ ///
3+ /// [`SafelyIndex`] is implemented on YAML objects to provide the [`get`] method to conveniently
4+ /// access sequence or mapping elements. This is similar to [`Index`]ing, except that the [`get`]
5+ /// method returns an [`Option`], using [`None`] rather than panicking when the requested index is
6+ /// out of range.
7+ ///
8+ /// [`get`]: SafelyIndex::get
9+ /// [`Index`]: std::ops::Index
10+ pub trait SafelyIndex < Node = Self > {
11+ /// Access a field of the given YAML object.
12+ ///
13+ /// # Return
14+ /// If the given index is valid within `self`, [`Some`] is returned with a reference to the
15+ /// indexed object. If `self` is not indexable or the index is out of bounds, this function
16+ /// returns [`None`].
17+ fn get ( & self , key : impl Into < Accessor > ) -> Option < & Node > ;
618}
719
8- /// A way to access fields via the [`SafelyIndex`] trait
20+ /// A trait to index without panicking into a structure through an [`Accessor`] (mutable).
21+ ///
22+ /// [`SafelyIndexMut`] is implemented on YAML objects to provide the [`get_mut`] method to
23+ /// conveniently access sequence or mapping elements. This is similar to [`IndexMut`]ing, except
24+ /// that the [`get_mut`] method returns an [`Option`], using [`None`] rather than panicking when
25+ /// the requested index is out of range.
26+ ///
27+ /// [`get_mut`]: SafelyIndexMut::get_mut
28+ /// [`IndexMut`]: std::ops::Index
29+ pub trait SafelyIndexMut < Node = Self > {
30+ /// Access a field of the given YAML object (mutable).
31+ ///
32+ /// # Return
33+ /// If the given index is valid within `self`, [`Some`] is returned with a reference to the
34+ /// indexed object. If `self` is not indexable or the index is out of bounds, this function
35+ /// returns [`None`].
36+ fn get_mut ( & mut self , key : impl Into < Accessor > ) -> Option < & mut Node > ;
37+ }
38+
39+ /// A [`SafelyIndex`] / [`SafelyIndexMut`] accessor.
940pub enum Accessor {
10- /// Accessing a string field from a mapping
41+ /// Accessing a string field from a mapping.
1142 Field ( String ) ,
12- /// Accessing an element from a sequence
43+ /// Accessing an element from a sequence or a mapping.
1344 Index ( usize ) ,
1445}
1546
@@ -31,63 +62,26 @@ impl From<&str> for Accessor {
3162 }
3263}
3364
34- impl < Z : SafelyIndex > SafelyIndex < Z > for Option < Z > {
35- fn get ( & self , key : impl Into < Accessor > ) -> Option < & Z > {
65+ impl < Node : SafelyIndex > SafelyIndex < Node > for Option < Node > {
66+ fn get ( & self , key : impl Into < Accessor > ) -> Option < & Node > {
3667 self . as_ref ( ) . and_then ( |data| data. get ( key) )
3768 }
3869}
3970
40- impl < Z : SafelyIndex > SafelyIndex < Z > for Option < & Z > {
41- fn get ( & self , key : impl Into < Accessor > ) -> Option < & Z > {
42- self . as_ref ( ) . and_then ( |data| data. get ( key) )
71+ impl < Node : SafelyIndexMut > SafelyIndexMut < Node > for Option < Node > {
72+ fn get_mut ( & mut self , key : impl Into < Accessor > ) -> Option < & mut Node > {
73+ self . as_mut ( ) . and_then ( |data| data. get_mut ( key) )
4374 }
4475}
4576
46- impl < T : SafelyIndex > SafelyIndex < T > for & T {
47- fn get ( & self , key : impl Into < Accessor > ) -> Option < & T > {
48- ( * self ) . get ( key)
77+ impl < Node : SafelyIndex > SafelyIndex < Node > for Option < & Node > {
78+ fn get ( & self , key : impl Into < Accessor > ) -> Option < & Node > {
79+ self . as_ref ( ) . and_then ( |data| data . get ( key) )
4980 }
5081}
5182
52- #[ cfg( test) ]
53- mod test {
54- use std:: string:: ToString ;
55-
56- use crate :: { LoadableYamlNode , SafelyIndex , Yaml } ;
57-
58- #[ test]
59- fn indexing_into_available_structures ( ) {
60- let node = Yaml :: load_from_str (
61- r#"
62- person:
63- name: "Jim Halpert"
64- workplace:
65- - name: "Dunder Mifflin"
66- role: "Manager"
67- tenure_years: 5
68- "# ,
69- )
70- . unwrap ( )
71- . first ( )
72- . cloned ( )
73- . unwrap ( ) ;
74-
75- let name = node
76- . get ( "person" )
77- . get ( "name" )
78- . and_then ( |name| name. as_str ( ) )
79- . map ( ToString :: to_string) ;
80-
81- assert ! ( name. is_some_and( |n| n == "Jim Halpert" ) ) ;
82-
83- let role = node
84- . get ( "person" )
85- . get ( "workplace" )
86- . get ( 0 )
87- . get ( "role" . to_string ( ) ) //just for example...
88- . and_then ( |role| role. as_str ( ) )
89- . map ( ToString :: to_string) ;
90-
91- assert ! ( role. is_some_and( |r| r == "Manager" ) ) ;
83+ impl < Node : SafelyIndexMut > SafelyIndexMut < Node > for Option < & mut Node > {
84+ fn get_mut ( & mut self , key : impl Into < Accessor > ) -> Option < & mut Node > {
85+ self . as_mut ( ) . and_then ( |data| data. get_mut ( key) )
9286 }
9387}
0 commit comments