@@ -144,6 +144,113 @@ impl Fragmenter {
144144 let used = max_total - rest. len ( ) ;
145145 SendOutput :: Packet ( & mut out[ ..used] )
146146 }
147+
148+ pub fn fragment_vectored < ' f > (
149+ & mut self ,
150+ payload : & [ & [ u8 ] ] ,
151+ out : & ' f mut [ u8 ] ,
152+ ) -> SendOutput < ' f > {
153+ let total_payload_len =
154+ payload. iter ( ) . fold ( 0 , |acc, part| acc + part. len ( ) ) ;
155+ if total_payload_len < self . payload_used {
156+ // Caller is passing varying payload buffers
157+ debug ! ( "varying payload" ) ;
158+ return SendOutput :: failure ( Error :: BadArgument , self ) ;
159+ }
160+
161+ // Require at least MTU buffer size, to ensure that all non-end
162+ // fragments are the same size per the spec.
163+ if out. len ( ) < self . mtu {
164+ debug ! ( "small out buffer" ) ;
165+ return SendOutput :: failure ( Error :: BadArgument , self ) ;
166+ }
167+
168+ // Reserve header space, the remaining buffer keeps being
169+ // updated in `rest`
170+ let max_total = out. len ( ) . min ( self . mtu ) ;
171+ let ( h, mut rest) = out[ ..max_total] . split_at_mut ( MctpHeader :: LEN ) ;
172+
173+ // Append type byte
174+ if self . header . som {
175+ rest[ 0 ] = mctp:: encode_type_ic ( self . typ , self . ic ) ;
176+ rest = & mut rest[ 1 ..] ;
177+ }
178+
179+ let remaining_payload_len = total_payload_len - self . payload_used ;
180+ let l = remaining_payload_len. min ( rest. len ( ) ) ;
181+ let ( d, rest) = rest. split_at_mut ( l) ;
182+ copy_vectored ( payload, self . payload_used , d) ;
183+ self . payload_used += l;
184+
185+ // Add the header
186+ if self . payload_used == total_payload_len {
187+ self . header . eom = true ;
188+ }
189+ // OK unwrap: seq and tag are valid.
190+ h. copy_from_slice ( & self . header . encode ( ) . unwrap ( ) ) ;
191+
192+ self . header . som = false ;
193+ self . header . seq = ( self . header . seq + 1 ) & mctp:: MCTP_SEQ_MASK ;
194+
195+ let used = max_total - rest. len ( ) ;
196+ SendOutput :: Packet ( & mut out[ ..used] )
197+ }
198+ }
199+
200+ /// Copy data from a vectored src to dest
201+ ///
202+ /// Copies `dest.len()` bytes from payload to dest,
203+ /// starting after `offset` bytes.
204+ ///
205+ /// ## Panics
206+ ///
207+ /// This function will panic when not enough bytes are available to fill dest.
208+ /// Total size of `payload` has to be `atleast dest.len()` + `offset`.
209+ fn copy_vectored ( src : & [ & [ u8 ] ] , offset : usize , dest : & mut [ u8 ] ) {
210+ let mut i = 0 ;
211+
212+ while i < dest. len ( ) {
213+ let payload_index = i + offset;
214+ let next = get_sub_slice ( src, payload_index) ;
215+ let remaining = dest. len ( ) - i;
216+ if remaining > next. len ( ) {
217+ dest[ i..( i + next. len ( ) ) ] . copy_from_slice ( next) ;
218+ i += next. len ( ) ;
219+ } else {
220+ dest[ i..] . copy_from_slice ( & next[ ..remaining] ) ;
221+ return ;
222+ }
223+ }
224+ }
225+
226+ /// Get a slice of `vector` indexed by `offset`
227+ ///
228+ /// The `offset` is the absolute byte index.
229+ /// The returned slice is the remaining sub slice starting at `offset`.
230+ ///
231+ /// ## Panics
232+ ///
233+ /// Will panic when offset is larger than the size of `vector`.
234+ ///
235+ /// ## Example
236+ /// ```ignore
237+ /// # use mctp_estack::fragment::get_slice;
238+ /// let vector: &[&[u8]] = &[&[1, 2, 3], &[4, 5, 6]];
239+ ///
240+ /// let slice = get_slice(vector, 4);
241+ ///
242+ /// assert_eq!(slice, &[5, 6]);
243+ /// ```
244+ fn get_sub_slice < ' a > ( vector : & ' a [ & [ u8 ] ] , offset : usize ) -> & ' a [ u8 ] {
245+ let mut i = offset;
246+ for slice in vector {
247+ if i >= slice. len ( ) {
248+ i -= slice. len ( ) ;
249+ } else {
250+ return & slice[ i..] ;
251+ }
252+ }
253+ panic ! ( "offset for vector out of bounds" ) ;
147254}
148255
149256pub enum SendOutput < ' p > {
@@ -194,3 +301,41 @@ impl SendOutput<'_> {
194301 Self :: Error { err, cookie : None }
195302 }
196303}
304+
305+ #[ cfg( test) ]
306+ mod tests {
307+ #[ test]
308+ fn test_get_slice ( ) {
309+ use super :: get_sub_slice;
310+ let vector: & [ & [ u8 ] ] = & [ & [ 1 , 2 , 3 ] , & [ 4 , 5 , 6 ] , & [ 7 , 8 , 9 ] ] ;
311+ let slice = get_sub_slice ( vector, 4 ) ;
312+ assert_eq ! ( slice, & [ 5 , 6 ] ) ;
313+ let slice = get_sub_slice ( vector, 0 ) ;
314+ assert_eq ! ( slice, & [ 1 , 2 , 3 ] ) ;
315+ let slice = get_sub_slice ( vector, 3 ) ;
316+ assert_eq ! ( slice, & [ 4 , 5 , 6 ] ) ;
317+ }
318+ #[ test]
319+ fn test_copy_vectored ( ) {
320+ use super :: copy_vectored;
321+ let vector: & [ & [ u8 ] ] = & [ & [ 1 , 2 , 3 ] , & [ 4 , 5 ] , & [ 6 , 7 , 8 , 9 ] ] ;
322+
323+ let mut dest = [ 0 ; 6 ] ;
324+ copy_vectored ( vector, 1 , & mut dest) ;
325+ assert_eq ! ( & dest, & [ 2 , 3 , 4 , 5 , 6 , 7 ] ) ;
326+
327+ let mut dest = [ 0 ; 5 ] ;
328+ copy_vectored ( vector, 4 , & mut dest) ;
329+ assert_eq ! ( & dest, & [ 5 , 6 , 7 , 8 , 9 ] ) ;
330+
331+ let mut dest = [ 0 ; 9 ] ;
332+ copy_vectored ( vector, 0 , & mut dest) ;
333+ assert_eq ! ( & dest, & [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] ) ;
334+
335+ let vector: & [ & [ u8 ] ] = & [ & [ 1 , 2 , 3 ] ] ;
336+
337+ let mut dest = [ 0 ; 1 ] ;
338+ copy_vectored ( vector, 2 , & mut dest) ;
339+ assert_eq ! ( & dest, & [ 3 ] ) ;
340+ }
341+ }
0 commit comments