Skip to content

Commit 95f3a54

Browse files
committed
Setting return type of PhantomHints to Iterator
- return value of the function select_phantom_hints is an iterator rather than vector - adding utility function that zips nested vectors
1 parent 818dbdf commit 95f3a54

File tree

1 file changed

+143
-22
lines changed

1 file changed

+143
-22
lines changed

lightning-invoice/src/utils.rs

+143-22
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use lightning::util::logger::Logger;
1818
use secp256k1::PublicKey;
1919
use core::ops::Deref;
2020
use core::time::Duration;
21+
use core::iter::Iterator;
2122

2223
/// Utility to create an invoice that can be paid to one of multiple nodes, or a "phantom invoice."
2324
/// See [`PhantomKeysManager`] for more information on phantom node payments.
@@ -229,7 +230,7 @@ where
229230
///
230231
/// [`PhantomKeysManager`]: lightning::sign::PhantomKeysManager
231232
fn select_phantom_hints<L: Deref>(amt_msat: Option<u64>, phantom_route_hints: Vec<PhantomRouteHints>,
232-
logger: L) -> Vec<RouteHint>
233+
logger: L) -> impl Iterator<Item = RouteHint>
233234
where
234235
L::Target: Logger,
235236
{
@@ -267,29 +268,47 @@ where
267268
// the hints across our real nodes we add one hint from each in turn until no node has any hints
268269
// left (if one node has more hints than any other, these will accumulate at the end of the
269270
// vector).
270-
let mut invoice_hints: Vec<RouteHint> = Vec::new();
271-
let mut hint_idx = 0;
271+
const MAX_HINTS: usize = 3;
272272

273-
loop {
274-
let mut remaining_hints = false;
273+
zip_nested_vectors(phantom_hints, MAX_HINTS)
275274

276-
for hints in phantom_hints.iter() {
277-
if invoice_hints.len() == 3 {
278-
return invoice_hints
279-
}
280-
281-
if hint_idx < hints.len() {
282-
invoice_hints.push(hints[hint_idx].clone());
283-
remaining_hints = true
284-
}
285-
}
286-
287-
if !remaining_hints {
288-
return invoice_hints
289-
}
275+
}
290276

291-
hint_idx +=1;
292-
}
277+
// Zip multiple nested vectors
278+
// Similar to the zip method on a vector, it combines the vectors by index - zero index comes first
279+
// then second, etc.
280+
// The difference is that this function handles many or just one vector, whereas the builtin method
281+
// works on just two vectors.
282+
fn zip_nested_vectors<T: Clone>(vecs: Vec<Vec<T>>, result_size: usize) -> impl Iterator<Item = T> {
283+
let max_vector_length: usize = vecs.iter().map(|x| x.len()).max().unwrap();
284+
let mut hint_index = 0;
285+
let mut vector_index = 0;
286+
let number_inner_vectors: usize = vecs.len();
287+
let mut total_hints_returned = 0;
288+
289+
core::iter::from_fn(move || loop {
290+
let return_value = loop {
291+
if total_hints_returned == result_size || hint_index == max_vector_length {
292+
break None;
293+
};
294+
let my_value =
295+
if vecs[vector_index].len() != 0 && vecs[vector_index].len() >= hint_index {
296+
Some(vecs[vector_index][hint_index].clone())
297+
} else {
298+
None // no value retrieved - continue looping
299+
};
300+
vector_index += 1;
301+
if hint_index < max_vector_length && vector_index == number_inner_vectors {
302+
vector_index = 0;
303+
hint_index += 1;
304+
};
305+
if !my_value.is_none() {
306+
total_hints_returned += 1;
307+
break my_value;
308+
};
309+
};
310+
return return_value;
311+
})
293312
}
294313

295314
#[cfg(feature = "std")]
@@ -777,7 +796,7 @@ mod test {
777796
use lightning::routing::router::{PaymentParameters, RouteParameters};
778797
use lightning::util::test_utils;
779798
use lightning::util::config::UserConfig;
780-
use crate::utils::create_invoice_from_channelmanager_and_duration_since_epoch;
799+
use crate::utils::{create_invoice_from_channelmanager_and_duration_since_epoch, zip_nested_vectors};
781800
use std::collections::HashSet;
782801

783802
#[test]
@@ -1886,4 +1905,106 @@ mod test {
18861905
_ => panic!(),
18871906
}
18881907
}
1908+
1909+
1910+
#[test]
1911+
fn test_zip_nested_vectors() {
1912+
const TEST_RESULT_SIZE: usize = 3;
1913+
1914+
// two nested vectors
1915+
let a = vec![vec!["a0", "b0", "c0"], vec!["a1", "b1"]];
1916+
let result = zip_nested_vectors(a, TEST_RESULT_SIZE).collect::<Vec<_>>();
1917+
1918+
let expected = vec!["a0", "a1", "b0"];
1919+
assert_eq!(expected, result);
1920+
1921+
// test single nested vector
1922+
let a = vec![vec!["a0", "b0", "c0"]];
1923+
let result = zip_nested_vectors(a, TEST_RESULT_SIZE).collect::<Vec<_>>();
1924+
1925+
let expected = vec!["a0", "b0", "c0"];
1926+
assert_eq!(expected, result);
1927+
1928+
// test second vector with only one element
1929+
let a = vec![vec!["a0", "b0", "c0"], vec!["a1"]];
1930+
let result = zip_nested_vectors(a, TEST_RESULT_SIZE).collect::<Vec<_>>();
1931+
1932+
let expected = vec!["a0", "a1", "b0"];
1933+
assert_eq!(expected, result);
1934+
1935+
// test three nestend vectors
1936+
let a = vec![vec!["a0"], vec!["a1", "b1", "c1"], vec!["a2"]];
1937+
let result = zip_nested_vectors(a, TEST_RESULT_SIZE).collect::<Vec<_>>();
1938+
1939+
let expected = vec!["a0", "a1", "a2"];
1940+
assert_eq!(expected, result);
1941+
1942+
// test single nested vector with a single value
1943+
let a = vec![vec!["a0"]];
1944+
let result = zip_nested_vectors(a, TEST_RESULT_SIZE).collect::<Vec<_>>();
1945+
1946+
let expected = vec!["a0"];
1947+
assert_eq!(expected, result);
1948+
1949+
// test single empty nested vector
1950+
let a:Vec<Vec<&str>> = vec![vec![]];
1951+
let result = zip_nested_vectors(a, TEST_RESULT_SIZE).collect::<Vec<_>>();
1952+
let expected:Vec<&str> = vec![];
1953+
1954+
assert_eq!(expected, result);
1955+
1956+
// test first nested vector is empty
1957+
let a = vec![vec![], vec!["a1", "b1", "c1"]];
1958+
let result = zip_nested_vectors(a, TEST_RESULT_SIZE).collect::<Vec<_>>();
1959+
1960+
let expected = vec!["a1", "b1", "c1"];
1961+
assert_eq!(expected, result);
1962+
1963+
// test two empty vectors
1964+
let a:Vec<Vec<&str>> = vec![vec![], vec![]];
1965+
let result = zip_nested_vectors(a, TEST_RESULT_SIZE).collect::<Vec<_>>();
1966+
1967+
let expected:Vec<&str> = vec![];
1968+
assert_eq!(expected, result);
1969+
1970+
// test an empty vector amongst other filled vectors
1971+
let a = vec![
1972+
vec!["a0", "b0", "c0"],
1973+
vec![],
1974+
vec!["a1", "b1", "c1"],
1975+
vec!["a2", "b2", "c2"],
1976+
];
1977+
let result = zip_nested_vectors(a, TEST_RESULT_SIZE).collect::<Vec<_>>();
1978+
1979+
let expected = vec!["a0", "a1", "a2"];
1980+
assert_eq!(expected, result);
1981+
1982+
// test a filled vector between two empty vectors
1983+
let a = vec![vec![], vec!["a1", "b1", "c1"], vec![]];
1984+
let result = zip_nested_vectors(a, TEST_RESULT_SIZE).collect::<Vec<_>>();
1985+
1986+
let expected = vec!["a1", "b1", "c1"];
1987+
assert_eq!(expected, result);
1988+
1989+
// test an empty vector at the end of the vectors
1990+
let a = vec![vec!["a0", "b0", "c0"], vec![]];
1991+
let result = zip_nested_vectors(a, TEST_RESULT_SIZE).collect::<Vec<_>>();
1992+
1993+
let expected = vec!["a0", "b0", "c0"];
1994+
assert_eq!(expected, result);
1995+
1996+
// test multiple empty vectors amongst multiple filled vectors
1997+
let a = vec![
1998+
vec![],
1999+
vec!["a1", "b1", "c1"],
2000+
vec![],
2001+
vec!["a3", "b3"],
2002+
vec![],
2003+
];
2004+
2005+
let result = zip_nested_vectors(a, TEST_RESULT_SIZE).collect::<Vec<_>>();
2006+
2007+
let expected = vec!["a1", "a3", "b1"];
2008+
assert_eq!(expected, result);
2009+
}
18892010
}

0 commit comments

Comments
 (0)