@@ -840,8 +840,7 @@ pub impl ByteSpanImpl of ByteSpanTrait {
840840    }
841841
842842    ///  Gets the element(s) at the given index.
843-     ///  Accepts ranges (returns Option<ByteSpan>), and (to-be-implemented) single indices (returns
844-     ///  Option<u8>).
843+     ///  Accepts ranges (returns Option<ByteSpan>), and single indices (returns Option<u8>).
845844    #[feature(" get-trait" 
846845    fn  get <I , impl  TGet :  crate :: ops :: Get <ByteSpan , I >, + Drop <I >>(
847846        self :  @ ByteSpan , index :  I ,
@@ -913,6 +912,24 @@ impl ByteSpanGetRangeInclusive of crate::ops::Get<ByteSpan, crate::ops::RangeInc
913912    }
914913}
915914
915+ impl  ByteSpanGetUsize  of  crate :: ops :: Get <ByteSpan , usize > {
916+     type  Output  =  u8 ;
917+ 
918+     ///  Returns the byte at the given index.
919+     ///  If out of bounds: returns `None`.
920+     fn  get (self :  @ ByteSpan , index :  usize ) ->  Option <u8 > {
921+         helpers :: byte_at (self , index )
922+     }
923+ }
924+ 
925+ impl  ByteSpanIndex  of  core :: ops :: index :: IndexView <ByteSpan , usize > {
926+     type  Target  =  u8 ;
927+ 
928+     fn  index (self :  @ ByteSpan , index :  usize ) ->  u8  {
929+         ByteSpanTrait :: get (self , index ). expect (' Index out of bounds' 
930+     }
931+ }
932+ 
916933///  Trait for types that can be converted into a `ByteSpan`.
917934#[unstable(feature:  " byte-span" 
918935pub  trait  ToByteSpanTrait <C > {
@@ -957,18 +974,21 @@ fn shift_right(word: felt252, word_len: usize, n_bytes: usize) -> felt252 {
957974
958975mod  helpers  {
959976    use  core :: num :: traits :: Bounded ;
960-     use  crate :: bytes_31 :: BYTES_IN_BYTES31 ;
977+     use  crate :: bytes_31 :: { BYTES_IN_BYTES31 ,  Bytes31Trait , u8_at_ u256 } ;
961978    #[feature(" bounded-int-utils" 
962979    use  crate :: internal :: bounded_int :: {
963-         self, AddHelper , BoundedInt , ConstrainHelper , MulHelper , SubHelper , UnitInt , downcast ,
964-         upcast,
980+         self, AddHelper , BoundedInt , ConstrainHelper , DivRemHelper ,  MulHelper , SubHelper , UnitInt ,
981+         downcast,  upcast,
965982    };
966983    use  super :: {BYTES_IN_BYTES31_MINUS_ONE , ByteSpan , Bytes31Index };
967984
968985    type  BytesInBytes31Typed  =  UnitInt <{ BYTES_IN_BYTES31 . into() }>;
969986
970987    const  U32_MAX_TIMES_B31 :  felt252  =  Bounded :: <u32 >:: MAX . into () *  BYTES_IN_BYTES31 . into ();
971988    const  BYTES_IN_BYTES31_UNIT_INT :  BytesInBytes31Typed  =  downcast (BYTES_IN_BYTES31 ). unwrap ();
989+     const  NZ_BYTES_IN_BYTES31 :  NonZero <BytesInBytes31Typed > =  31 ;
990+     const  BYTES_IN_BYTES31_MINUS_ONE_TYPED :  UnitInt <{ BYTES_IN_BYTES31_MINUS_ONE . into() }> =  30 ;
991+     const  ONE_TYPED :  UnitInt <1 > =  1 ;
972992
973993    impl  U32ByB31  of  MulHelper <u32 , BytesInBytes31Typed > {
974994        type  Result  =  BoundedInt <0 , U32_MAX_TIMES_B31 >;
@@ -986,6 +1006,50 @@ mod helpers {
9861006            >;
9871007    }
9881008
1009+     //  For byte_at: usize + BoundedInt<0,30>
1010+     impl  UsizeAddBytes31Index  of  AddHelper <usize , Bytes31Index > {
1011+         type  Result  = 
1012+             BoundedInt <0 , { Bounded :: <usize >:: MAX . into () +  BYTES_IN_BYTES31_MINUS_ONE . into () }>;
1013+     }
1014+ 
1015+     //  For byte_at: div_rem of (usize + BoundedInt<0,30>) by 31
1016+     const  USIZE_PLUS_30_DIV_31 :  felt252  =  0x8421085 ; //  (usize::MAX + 30) / 31 = 138547333
1017+     impl  UsizePlusBytes31IndexDivRemB31  of  DivRemHelper <
1018+         UsizeAddBytes31Index :: Result , BytesInBytes31Typed ,
1019+     > {
1020+         type  DivT  =  BoundedInt <0 , USIZE_PLUS_30_DIV_31 >;
1021+         type  RemT  =  Bytes31Index ;
1022+     }
1023+ 
1024+     //  For byte_at: 30 - BoundedInt<0,30>
1025+     impl  B30SubBytes31Index  of  SubHelper <
1026+         UnitInt <{ BYTES_IN_BYTES31_MINUS_ONE . into() }>, Bytes31Index ,
1027+     > {
1028+         type  Result  =  Bytes31Index ;
1029+     }
1030+ 
1031+     //  For byte_at: BoundedInt<0,30> - 1
1032+     impl  Bytes31IndexSub1  of  SubHelper <Bytes31Index , UnitInt <1 >> {
1033+         type  Result  =  BoundedInt <- 1 , { BYTES_IN_BYTES31_MINUS_ONE . into() -  1  }>;
1034+     }
1035+ 
1036+     //  For byte_at: (BoundedInt<0,30> - 1) - BoundedInt<0,30>
1037+     impl  Bytes31IndexMinus1SubBytes31Index  of  SubHelper <Bytes31IndexSub1 :: Result , Bytes31Index > {
1038+         type  Result  = 
1039+             BoundedInt <
1040+                 { - BYTES_IN_BYTES31_MINUS_ONE . into() -  1  },
1041+                 { BYTES_IN_BYTES31_MINUS_ONE . into() -  1  },
1042+             >;
1043+     }
1044+ 
1045+     //  For byte_at: split BoundedInt<-31, 29> at 0.
1046+     impl  ConstrainRemainderIndexAt0  of  bounded_int :: ConstrainHelper <
1047+         Bytes31IndexMinus1SubBytes31Index :: Result , 0 ,
1048+     > {
1049+         type  LowT  =  BoundedInt <{ - BYTES_IN_BYTES31_MINUS_ONE . into() -  1  }, - 1 >;
1050+         type  HighT  =  BoundedInt <0 , { BYTES_IN_BYTES31_MINUS_ONE . into() -  1  }>;
1051+     }
1052+ 
9891053    ///  Calculates the length of a `ByteSpan` in bytes.
9901054    pub  fn  calc_bytespan_len (span :  ByteSpan ) ->  usize  {
9911055        let  data_bytes  =  bounded_int :: mul (span . data. len (), BYTES_IN_BYTES31_UNIT_INT );
@@ -1075,5 +1139,39 @@ mod helpers {
10751139    pub  fn  length_minus_one (len :  BoundedInt <1 , 31 >) ->  Bytes31Index  {
10761140        bounded_int :: sub (len , 1 )
10771141    }
1142+     ///  Returns the byte at the given index in the ByteSpan.
1143+     ///  If out of bounds: returns `None`.
1144+     pub  fn  byte_at (self :  @ ByteSpan , index :  usize ) ->  Option <u8 > {
1145+         let  absolute_index  =  bounded_int :: add (index , * self . first_char_start_offset);
1146+         let  (word_index_bounded , msb_index ) =  bounded_int :: div_rem (
1147+             absolute_index , NZ_BYTES_IN_BYTES31 ,
1148+         );
1149+ 
1150+         let  word_index  =  upcast (word_index_bounded );
1151+         match  self . data. get (word_index ) {
1152+             Some (word ) =>  {
1153+                 //  Convert from MSB to LSB indexing.
1154+                 let  lsb_index  =  bounded_int :: sub (BYTES_IN_BYTES31_MINUS_ONE_TYPED , msb_index );
1155+                 Some (word . at (upcast (lsb_index )))
1156+             },
1157+             None  =>  {
1158+                 //  Word index must equal data.len() for remainder word.
1159+                 if  word_index  !=  self . data. len () {
1160+                     return  None ;
1161+                 }
1162+ 
1163+                 //  Compute LSB index: remainder_len - 1 - msb_index.
1164+                 let  lsb_index_bounded  =  bounded_int :: sub (
1165+                     bounded_int :: sub (* self . remainder_len, ONE_TYPED ), msb_index ,
1166+                 );
1167+ 
1168+                 //  Check if in bounds and extract non-negative index.
1169+                 let  Err (lsb_index ) =  bounded_int :: constrain :: <_ , 0 >(lsb_index_bounded ) else  {
1170+                     return  None ; //  Out of bounds: index >= remainder_len.
1171+                 };
1172+                 Some (u8_at_u256 ((* self . remainder_word). into (), upcast (lsb_index )))
1173+             },
1174+         }
1175+     }
10781176}
10791177pub (crate ) use  helpers :: len_parts;
0 commit comments