@@ -456,7 +456,7 @@ impl Vfs {
456456pub struct OpenFile {
457457 // The list of blobs
458458 content : Vec < DataId > ,
459- offsets : ContentOffset ,
459+ startpoints : ContentStartpoints ,
460460}
461461
462462impl OpenFile {
@@ -468,26 +468,32 @@ impl OpenFile {
468468 /// * `node` - The `Node` to create the `OpenFile` for
469469 ///
470470 /// # Errors
471- ///
472- // TODO: Document errors
471+ /// - If the index for the needed data blobs cannot be read
473472 ///
474473 /// # Returns
475474 ///
476475 /// The created `OpenFile`
477- ///
478- /// # Panics
479- ///
480- /// * Panics if the `Node` has no content
481- pub fn from_node < P , S : IndexedFull > ( repo : & Repository < P , S > , node : & Node ) -> Self {
482- let content: Vec < _ > = node. content . as_ref ( ) . unwrap ( ) . clone ( ) ;
483-
484- let offsets = ContentOffset :: from_sizes (
485- content
486- . iter ( )
487- . map ( |id| repo. index ( ) . get_data ( id) . unwrap ( ) . data_length ( ) as usize ) ,
488- ) ;
489-
490- Self { content, offsets }
476+ pub ( crate ) fn from_node < P , S : IndexedFull > (
477+ repo : & Repository < P , S > ,
478+ node : & Node ,
479+ ) -> RusticResult < Self > {
480+ let content: Vec < _ > = node. content . clone ( ) . unwrap_or_default ( ) ;
481+
482+ let startpoints = ContentStartpoints :: from_sizes ( content. iter ( ) . map ( |id| {
483+ Ok ( repo
484+ . index ( )
485+ . get_data ( id)
486+ . ok_or_else ( || {
487+ RusticError :: new ( ErrorKind :: Vfs , "blob {blob} is not contained in index" )
488+ . attach_context ( "blob" , id. to_string ( ) )
489+ } ) ?
490+ . data_length ( ) as usize )
491+ } ) ) ?;
492+
493+ Ok ( Self {
494+ content,
495+ startpoints,
496+ } )
491497 }
492498
493499 /// Read the `OpenFile` at the given `offset` from the `repo`.
@@ -500,7 +506,7 @@ impl OpenFile {
500506 ///
501507 /// # Errors
502508 ///
503- // TODO: Document errors
509+ /// - if reading the needed blob(s) from the backend fails
504510 ///
505511 /// # Returns
506512 ///
@@ -513,7 +519,7 @@ impl OpenFile {
513519 offset : usize ,
514520 mut length : usize ,
515521 ) -> RusticResult < Bytes > {
516- let ( mut i, mut offset) = self . offsets . offset ( offset) ;
522+ let ( mut i, mut offset) = self . startpoints . compute_start ( offset) ;
517523
518524 let mut result = BytesMut :: with_capacity ( length) ;
519525
@@ -527,43 +533,41 @@ impl OpenFile {
527533 }
528534
529535 let to_copy = ( data. len ( ) - offset) . min ( length) ;
530-
531536 result. extend_from_slice ( & data[ offset..offset + to_copy] ) ;
532-
533537 offset = 0 ;
534-
535538 length -= to_copy;
536-
537539 i += 1 ;
538540 }
539541
540542 Ok ( result. into ( ) )
541543 }
542544}
543545
546+ // helper struct holding blob startpoints of the content
544547#[ derive( Debug ) ]
545- struct ContentOffset ( Vec < usize > ) ;
548+ struct ContentStartpoints ( Vec < usize > ) ;
546549
547- impl ContentOffset {
548- fn from_sizes ( sizes : impl IntoIterator < Item = usize > ) -> Self {
550+ impl ContentStartpoints {
551+ fn from_sizes ( sizes : impl IntoIterator < Item = RusticResult < usize > > ) -> RusticResult < Self > {
549552 let mut start = 0 ;
550553 let mut offsets: Vec < _ > = sizes
551554 . into_iter ( )
552- . map ( |size| {
555+ . map ( |size| -> RusticResult < _ > {
553556 let starts_at = start;
554- start += size;
555- starts_at
557+ start += size? ;
558+ Ok ( starts_at)
556559 } )
557- . collect ( ) ;
560+ . collect :: < RusticResult < _ > > ( ) ? ;
558561
559562 if !offsets. is_empty ( ) {
560563 // offsets is assumed to be partitioned, so we add a starts_at:MAX entry
561564 offsets. push ( usize:: MAX ) ;
562565 }
563- Self ( offsets)
566+ Ok ( Self ( offsets) )
564567 }
565568
566- fn offset ( & self , mut offset : usize ) -> ( usize , usize ) {
569+ // compute the correct blobid and effective offset from a file offset
570+ fn compute_start ( & self , mut offset : usize ) -> ( usize , usize ) {
567571 if self . 0 . is_empty ( ) {
568572 return ( 0 , 0 ) ;
569573 }
@@ -580,26 +584,31 @@ impl ContentOffset {
580584mod tests {
581585 use super :: * ;
582586
587+ // helper func
588+ fn startpoints_from_ok_sizes ( sizes : impl IntoIterator < Item = usize > ) -> ContentStartpoints {
589+ ContentStartpoints :: from_sizes ( sizes. into_iter ( ) . map ( Ok ) ) . unwrap ( )
590+ }
591+
583592 #[ test]
584593 fn content_offsets_empty_sizes ( ) {
585- let offsets = ContentOffset :: from_sizes ( [ ] ) ;
586- assert_eq ! ( offsets. offset ( 0 ) , ( 0 , 0 ) ) ;
587- assert_eq ! ( offsets. offset ( 42 ) , ( 0 , 0 ) ) ;
594+ let offsets = startpoints_from_ok_sizes ( [ ] ) ;
595+ assert_eq ! ( offsets. compute_start ( 0 ) , ( 0 , 0 ) ) ;
596+ assert_eq ! ( offsets. compute_start ( 42 ) , ( 0 , 0 ) ) ;
588597 }
589598
590599 #[ test]
591600 fn content_offsets_size ( ) {
592- let offsets = ContentOffset :: from_sizes ( [ 15 ] ) ;
593- assert_eq ! ( offsets. offset ( 0 ) , ( 0 , 0 ) ) ;
594- assert_eq ! ( offsets. offset ( 5 ) , ( 0 , 5 ) ) ;
595- assert_eq ! ( offsets. offset ( 20 ) , ( 0 , 20 ) ) ;
601+ let offsets = startpoints_from_ok_sizes ( [ 15 ] ) ;
602+ assert_eq ! ( offsets. compute_start ( 0 ) , ( 0 , 0 ) ) ;
603+ assert_eq ! ( offsets. compute_start ( 5 ) , ( 0 , 5 ) ) ;
604+ assert_eq ! ( offsets. compute_start ( 20 ) , ( 0 , 20 ) ) ;
596605 }
597606 #[ test]
598607 fn content_offsets_sizes ( ) {
599- let offsets = ContentOffset :: from_sizes ( [ 15 , 24 ] ) ;
600- assert_eq ! ( offsets. offset ( 0 ) , ( 0 , 0 ) ) ;
601- assert_eq ! ( offsets. offset ( 5 ) , ( 0 , 5 ) ) ;
602- assert_eq ! ( offsets. offset ( 20 ) , ( 1 , 5 ) ) ;
603- assert_eq ! ( offsets. offset ( 42 ) , ( 1 , 27 ) ) ;
608+ let offsets = startpoints_from_ok_sizes ( [ 15 , 24 ] ) ;
609+ assert_eq ! ( offsets. compute_start ( 0 ) , ( 0 , 0 ) ) ;
610+ assert_eq ! ( offsets. compute_start ( 5 ) , ( 0 , 5 ) ) ;
611+ assert_eq ! ( offsets. compute_start ( 20 ) , ( 1 , 5 ) ) ;
612+ assert_eq ! ( offsets. compute_start ( 42 ) , ( 1 , 27 ) ) ;
604613 }
605614}
0 commit comments