github.com/anacrolix/torrent@v1.61.0/metainfo/piece.go (about) 1 package metainfo 2 3 import ( 4 "fmt" 5 "iter" 6 7 g "github.com/anacrolix/generics" 8 "github.com/anacrolix/missinggo/v2/panicif" 9 ) 10 11 type Piece struct { 12 Info *Info // Can we embed the fields here instead, or is it something to do with saving memory? 13 i PieceIndex 14 } 15 16 func (p Piece) String() string { 17 return fmt.Sprintf("metainfo.Piece(Info.Name=%q, i=%v)", p.Info.Name, p.i) 18 } 19 20 type PieceIndex = int 21 22 func (p Piece) Length() int64 { 23 if p.Info.HasV2() { 24 var offset int64 25 pieceLength := p.Info.PieceLength 26 lastFileEnd := int64(0) 27 for fi := range p.Info.FileTree.upvertedFiles(pieceLength) { 28 // I don't think we need to track offset ourselves. 29 panicif.NotEq(offset, fi.TorrentOffset) 30 fileStartPiece := int(offset / pieceLength) 31 if fileStartPiece > p.i { 32 break 33 } 34 lastFileEnd = offset + fi.Length 35 offset = (lastFileEnd + pieceLength - 1) / pieceLength * pieceLength 36 } 37 ret := min(lastFileEnd-int64(p.i)*pieceLength, pieceLength) 38 if ret <= 0 { 39 panic(ret) 40 } 41 return ret 42 } 43 return p.V1Length() 44 } 45 46 func iterLast[T any](i iter.Seq[T]) (last g.Option[T]) { 47 for t := range i { 48 last.Set(t) 49 } 50 return 51 } 52 53 func (p Piece) V1Length() int64 { 54 i := p.i 55 lastPiece := p.Info.NumPieces() - 1 56 switch { 57 case 0 <= i && i < lastPiece: 58 return p.Info.PieceLength 59 case lastPiece >= 0 && i == lastPiece: 60 lastFile := iterLast(p.Info.UpvertedV1Files()).Unwrap() 61 length := lastFile.TorrentOffset + lastFile.Length - int64(i)*p.Info.PieceLength 62 if length <= 0 || length > p.Info.PieceLength { 63 panic(length) 64 } 65 return length 66 default: 67 panic(i) 68 } 69 } 70 71 func (p Piece) Offset() int64 { 72 return int64(p.i) * p.Info.PieceLength 73 } 74 75 func (p Piece) V1Hash() (ret g.Option[Hash]) { 76 if !p.Info.HasV1() { 77 return 78 } 79 copy(ret.Value[:], p.Info.Pieces[p.i*HashSize:(p.i+1)*HashSize]) 80 ret.Ok = true 81 return 82 } 83 84 func (p Piece) Index() int { 85 return p.i 86 }