@@ -61,61 +61,66 @@ fn try_to_string<'a>(values: &'a Map<String, Value>, key: &'a str) -> Result<&'a
6161 }
6262}
6363
64- /// A single value in the parameter list for the `try_to_strings`
65- /// function.
66- pub ( crate ) type MapLookup < ' a > = ( & ' a Map < String , Value > , & ' a str ) ;
64+ # [ cfg ( feature = "build-metadata" ) ]
65+ pub ( crate ) mod build_metadata_testing {
66+ use super :: * ;
6767
68- /// Given a constant-size slice of `MapLookup`s, attempt to look up the
69- /// string value in each `MapLookup`'s map (the first tuple element) for
70- /// that `MapLookup`'s key (the second tuple element). If the lookup
71- /// succeeded, attempt to convert the resulting value to a string. Return
72- /// `Ok` with all the successfully looked-up string values, or `Err`
73- /// if any one or more lookups or string conversions failed.
74- pub ( crate ) fn try_to_strings < ' a , const NUM : usize > (
75- lookups : [ MapLookup < ' a > ; NUM ] ,
76- ) -> Result < [ & ' a str ; NUM ] > {
77- // Note (from arschles) about this code:
78- //
79- // In theory, there's a way to write this function in the functional
80- // programming (FP) style -- e.g. with a fold, map, flat_map, or
81- // something similar -- and without any mutability.
82- //
83- // In practice, however, since we're taking in a statically-sized slice,
84- // and we are expected to return a statically-sized slice of the same
85- // size, we are more limited in what we can do. There is a way to design
86- // a fold or flat_map to iterate over the lookups parameter and attempt to
87- // transform each MapLookup into the string value at that key.
88- //
89- // I wrote that code, which I'll called the "FP code" hereafter, and
90- // noticed two things:
91- //
92- // - It required several places where I had to explicitly deal with long
93- // and complex (in my opinion) types
94- // - It wasn't much more succinct or shorter than the code herein
95- //
96- // The FP code is functionally "pure" and maybe fun to write (if you like
97- // Rust or you love FP), but not fun to read. In fact, because of all the
98- // explicit type ceremony, I bet it'd make even the most hardcore Haskell
99- // programmer blush.
100- //
101- // So, I've decided to use a little bit of mutability to implement this
102- // function in a way I think most programmers would agree is easier to
103- // reason about and understand quickly.
104- //
105- // Final performance note:
106- //
107- // It's likely, but not certain, that the FP code is probably not
108- // significantly more memory efficient than this, since the compiler knows
109- // the size of both the input and output slices. Plus, this is test code,
110- // so even if this were 2x slower, I'd still argue the ease of
111- // understanding is more valuable than the (relatively small) memory
112- // savings.
113- let mut ret_slc: [ & ' a str ; NUM ] = [ "" ; NUM ] ;
114- for ( idx, lookup) in lookups. iter ( ) . enumerate ( ) {
115- let map = lookup. 0 ;
116- let key = lookup. 1 ;
117- let val = try_to_string ( map, key) ?;
118- ret_slc[ idx] = val
68+ /// A single value in the parameter list for the `try_to_strings`
69+ /// function.
70+ pub ( crate ) type MapLookup < ' a > = ( & ' a Map < String , Value > , & ' a str ) ;
71+
72+ /// Given a constant-size slice of `MapLookup`s, attempt to look up the
73+ /// string value in each `MapLookup`'s map (the first tuple element) for
74+ /// that `MapLookup`'s key (the second tuple element). If the lookup
75+ /// succeeded, attempt to convert the resulting value to a string. Return
76+ /// `Ok` with all the successfully looked-up string values, or `Err`
77+ /// if any one or more lookups or string conversions failed.
78+ pub ( crate ) fn try_to_strings < ' a , const NUM : usize > (
79+ lookups : [ MapLookup < ' a > ; NUM ] ,
80+ ) -> Result < [ & ' a str ; NUM ] > {
81+ // Note (from arschles) about this code:
82+ //
83+ // In theory, there's a way to write this function in the functional
84+ // programming (FP) style -- e.g. with a fold, map, flat_map, or
85+ // something similar -- and without any mutability.
86+ //
87+ // In practice, however, since we're taking in a statically-sized slice,
88+ // and we are expected to return a statically-sized slice of the same
89+ // size, we are more limited in what we can do. There is a way to design
90+ // a fold or flat_map to iterate over the lookups parameter and attempt to
91+ // transform each MapLookup into the string value at that key.
92+ //
93+ // I wrote that code, which I'll called the "FP code" hereafter, and
94+ // noticed two things:
95+ //
96+ // - It required several places where I had to explicitly deal with long
97+ // and complex (in my opinion) types
98+ // - It wasn't much more succinct or shorter than the code herein
99+ //
100+ // The FP code is functionally "pure" and maybe fun to write (if you like
101+ // Rust or you love FP), but not fun to read. In fact, because of all the
102+ // explicit type ceremony, I bet it'd make even the most hardcore Haskell
103+ // programmer blush.
104+ //
105+ // So, I've decided to use a little bit of mutability to implement this
106+ // function in a way I think most programmers would agree is easier to
107+ // reason about and understand quickly.
108+ //
109+ // Final performance note:
110+ //
111+ // It's likely, but not certain, that the FP code is probably not
112+ // significantly more memory efficient than this, since the compiler knows
113+ // the size of both the input and output slices. Plus, this is test code,
114+ // so even if this were 2x slower, I'd still argue the ease of
115+ // understanding is more valuable than the (relatively small) memory
116+ // savings.
117+ let mut ret_slc: [ & ' a str ; NUM ] = [ "" ; NUM ] ;
118+ for ( idx, lookup) in lookups. iter ( ) . enumerate ( ) {
119+ let map = lookup. 0 ;
120+ let key = lookup. 1 ;
121+ let val = try_to_string ( map, key) ?;
122+ ret_slc[ idx] = val
123+ }
124+ Ok ( ret_slc)
119125 }
120- Ok ( ret_slc)
121126}
0 commit comments