@@ -240,8 +240,96 @@ impl SocketAddrs {
240240 pub ( super ) fn len ( & self ) -> usize {
241241 self . iter . as_slice ( ) . len ( )
242242 }
243+
244+ /// Create an interleaved address iterator per RFC 8305 (Happy Eyeballs v2) Section 4.
245+ ///
246+ /// Takes `first_family_count` addresses from the preferred family,
247+ /// then interleaves remaining addresses: one fallback, one preferred, repeat.
248+ ///
249+ /// Input: `[v6_1, v6_2, v4_1, v4_2]` (IPv6 preferred)
250+ /// Output: `[v6_1, v4_1, v6_2, v4_2]` (with `first_family_count=1`)
251+ pub ( super ) fn interleave_by_family ( self , first_family_count : usize ) -> InterleavedAddrs {
252+ InterleavedAddrs :: new ( self , first_family_count)
253+ }
254+ }
255+
256+ /// Iterator over addresses interleaved by family per RFC 8305 (Happy Eyeballs v2).
257+ pub ( super ) struct InterleavedAddrs {
258+ inner : vec:: IntoIter < SocketAddr > ,
259+ total : usize ,
260+ }
261+
262+ impl InterleavedAddrs {
263+ fn new ( addrs : SocketAddrs , first_family_count : usize ) -> Self {
264+ let addrs: Vec < _ > = addrs. iter . collect ( ) ;
265+ let total = addrs. len ( ) ;
266+
267+ if addrs. is_empty ( ) {
268+ return InterleavedAddrs {
269+ inner : Vec :: new ( ) . into_iter ( ) ,
270+ total : 0 ,
271+ } ;
272+ }
273+
274+ // Determine preferred family from first address
275+ let prefer_ipv6 = addrs[ 0 ] . is_ipv6 ( ) ;
276+
277+ let ( mut preferred, fallback) : ( Vec < _ > , Vec < _ > ) = if prefer_ipv6 {
278+ addrs. into_iter ( ) . partition ( |a| a. is_ipv6 ( ) )
279+ } else {
280+ addrs. into_iter ( ) . partition ( |a| a. is_ipv4 ( ) )
281+ } ;
282+
283+ let mut result = Vec :: with_capacity ( total) ;
284+
285+ // Take first_family_count from preferred
286+ let take_count = first_family_count. min ( preferred. len ( ) ) ;
287+ result. extend ( preferred. drain ( ..take_count) ) ;
288+
289+ // Interleave remaining: fallback, preferred, fallback, preferred...
290+ let mut pref_iter = preferred. into_iter ( ) ;
291+ let mut fall_iter = fallback. into_iter ( ) ;
292+
293+ loop {
294+ match ( fall_iter. next ( ) , pref_iter. next ( ) ) {
295+ ( Some ( f) , Some ( p) ) => {
296+ result. push ( f) ;
297+ result. push ( p) ;
298+ }
299+ ( Some ( f) , None ) => result. push ( f) ,
300+ ( None , Some ( p) ) => result. push ( p) ,
301+ ( None , None ) => break ,
302+ }
303+ }
304+
305+ InterleavedAddrs {
306+ inner : result. into_iter ( ) ,
307+ total,
308+ }
309+ }
310+
311+ /// Total number of addresses (original count before any iteration).
312+ pub ( super ) fn total ( & self ) -> usize {
313+ self . total
314+ }
315+ }
316+
317+ impl Iterator for InterleavedAddrs {
318+ type Item = SocketAddr ;
319+
320+ #[ inline]
321+ fn next ( & mut self ) -> Option < SocketAddr > {
322+ self . inner . next ( )
323+ }
324+
325+ #[ inline]
326+ fn size_hint ( & self ) -> ( usize , Option < usize > ) {
327+ self . inner . size_hint ( )
328+ }
243329}
244330
331+ impl ExactSizeIterator for InterleavedAddrs { }
332+
245333impl Iterator for SocketAddrs {
246334 type Item = SocketAddr ;
247335 #[ inline]
@@ -357,4 +445,101 @@ mod tests {
357445 assert_eq ! ( name. as_str( ) , DOMAIN ) ;
358446 assert_eq ! ( name. to_string( ) , DOMAIN ) ;
359447 }
448+
449+ // === RFC 8305 Address Interleaving Tests ===
450+
451+ #[ test]
452+ fn test_interleave_by_family_basic ( ) {
453+ // IPv6 preferred (first in list), interleave with IPv4
454+ let v6_1: SocketAddr = "[2001:db8::1]:80" . parse ( ) . unwrap ( ) ;
455+ let v6_2: SocketAddr = "[2001:db8::2]:80" . parse ( ) . unwrap ( ) ;
456+ let v4_1: SocketAddr = "192.0.2.1:80" . parse ( ) . unwrap ( ) ;
457+ let v4_2: SocketAddr = "192.0.2.2:80" . parse ( ) . unwrap ( ) ;
458+
459+ let addrs = SocketAddrs :: new ( vec ! [ v6_1, v6_2, v4_1, v4_2] ) ;
460+ let result: Vec < _ > = addrs. interleave_by_family ( 1 ) . collect ( ) ;
461+
462+ // RFC 8305: first_family_count=1 means v6, v4, v6, v4...
463+ assert_eq ! ( result, vec![ v6_1, v4_1, v6_2, v4_2] ) ;
464+ }
465+
466+ #[ test]
467+ fn test_interleave_by_family_empty ( ) {
468+ let addrs = SocketAddrs :: new ( vec ! [ ] ) ;
469+ let result: Vec < _ > = addrs. interleave_by_family ( 1 ) . collect ( ) ;
470+ assert ! ( result. is_empty( ) ) ;
471+ }
472+
473+ #[ test]
474+ fn test_interleave_by_family_single_family ( ) {
475+ // All IPv4 - no interleaving needed
476+ let v4_1: SocketAddr = "192.0.2.1:80" . parse ( ) . unwrap ( ) ;
477+ let v4_2: SocketAddr = "192.0.2.2:80" . parse ( ) . unwrap ( ) ;
478+ let v4_3: SocketAddr = "192.0.2.3:80" . parse ( ) . unwrap ( ) ;
479+
480+ let addrs = SocketAddrs :: new ( vec ! [ v4_1, v4_2, v4_3] ) ;
481+ let result: Vec < _ > = addrs. interleave_by_family ( 1 ) . collect ( ) ;
482+
483+ assert_eq ! ( result, vec![ v4_1, v4_2, v4_3] ) ;
484+ }
485+
486+ #[ test]
487+ fn test_interleave_by_family_count_2 ( ) {
488+ // first_family_count=2: take 2 from preferred, then interleave
489+ let v6_1: SocketAddr = "[2001:db8::1]:80" . parse ( ) . unwrap ( ) ;
490+ let v6_2: SocketAddr = "[2001:db8::2]:80" . parse ( ) . unwrap ( ) ;
491+ let v6_3: SocketAddr = "[2001:db8::3]:80" . parse ( ) . unwrap ( ) ;
492+ let v4_1: SocketAddr = "192.0.2.1:80" . parse ( ) . unwrap ( ) ;
493+ let v4_2: SocketAddr = "192.0.2.2:80" . parse ( ) . unwrap ( ) ;
494+
495+ let addrs = SocketAddrs :: new ( vec ! [ v6_1, v6_2, v6_3, v4_1, v4_2] ) ;
496+ let result: Vec < _ > = addrs. interleave_by_family ( 2 ) . collect ( ) ;
497+
498+ // First 2 v6, then interleave: v4, v6, v4
499+ assert_eq ! ( result, vec![ v6_1, v6_2, v4_1, v6_3, v4_2] ) ;
500+ }
501+
502+ #[ test]
503+ fn test_interleave_by_family_count_0 ( ) {
504+ // first_family_count=0: immediate interleave, fallback first
505+ let v6_1: SocketAddr = "[2001:db8::1]:80" . parse ( ) . unwrap ( ) ;
506+ let v6_2: SocketAddr = "[2001:db8::2]:80" . parse ( ) . unwrap ( ) ;
507+ let v4_1: SocketAddr = "192.0.2.1:80" . parse ( ) . unwrap ( ) ;
508+ let v4_2: SocketAddr = "192.0.2.2:80" . parse ( ) . unwrap ( ) ;
509+
510+ let addrs = SocketAddrs :: new ( vec ! [ v6_1, v6_2, v4_1, v4_2] ) ;
511+ let result: Vec < _ > = addrs. interleave_by_family ( 0 ) . collect ( ) ;
512+
513+ // Fallback first: v4, v6, v4, v6
514+ assert_eq ! ( result, vec![ v4_1, v6_1, v4_2, v6_2] ) ;
515+ }
516+
517+ #[ test]
518+ fn test_interleave_by_family_count_exceeds ( ) {
519+ // first_family_count exceeds available preferred addresses
520+ let v6_1: SocketAddr = "[2001:db8::1]:80" . parse ( ) . unwrap ( ) ;
521+ let v4_1: SocketAddr = "192.0.2.1:80" . parse ( ) . unwrap ( ) ;
522+ let v4_2: SocketAddr = "192.0.2.2:80" . parse ( ) . unwrap ( ) ;
523+
524+ let addrs = SocketAddrs :: new ( vec ! [ v6_1, v4_1, v4_2] ) ;
525+ let result: Vec < _ > = addrs. interleave_by_family ( 5 ) . collect ( ) ;
526+
527+ // Only 1 v6, take it, then all v4s
528+ assert_eq ! ( result, vec![ v6_1, v4_1, v4_2] ) ;
529+ }
530+
531+ #[ test]
532+ fn test_interleave_by_family_ipv4_preferred ( ) {
533+ // IPv4 first in list means IPv4 is preferred
534+ let v4_1: SocketAddr = "192.0.2.1:80" . parse ( ) . unwrap ( ) ;
535+ let v4_2: SocketAddr = "192.0.2.2:80" . parse ( ) . unwrap ( ) ;
536+ let v6_1: SocketAddr = "[2001:db8::1]:80" . parse ( ) . unwrap ( ) ;
537+ let v6_2: SocketAddr = "[2001:db8::2]:80" . parse ( ) . unwrap ( ) ;
538+
539+ let addrs = SocketAddrs :: new ( vec ! [ v4_1, v4_2, v6_1, v6_2] ) ;
540+ let result: Vec < _ > = addrs. interleave_by_family ( 1 ) . collect ( ) ;
541+
542+ // v4 preferred: v4, v6, v4, v6
543+ assert_eq ! ( result, vec![ v4_1, v6_1, v4_2, v6_2] ) ;
544+ }
360545}
0 commit comments