Skip to content

Commit 245bd93

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 245bd93

File tree

1 file changed

+152
-22
lines changed

1 file changed

+152
-22
lines changed

lightning-invoice/src/utils.rs

+152-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,48 @@ 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+
// todo : change name
295+
let hint_value =
296+
if vecs[vector_index].len() != 0 && vecs[vector_index].len() > hint_index {
297+
Some(vecs[vector_index][hint_index].clone())
298+
} else {
299+
None // no value retrieved - continue looping
300+
};
301+
vector_index += 1;
302+
if hint_index < max_vector_length && vector_index == number_inner_vectors {
303+
vector_index = 0;
304+
hint_index += 1;
305+
};
306+
if !hint_value.is_none() {
307+
total_hints_returned += 1;
308+
break hint_value;
309+
};
310+
};
311+
return return_value;
312+
})
293313
}
294314

295315
#[cfg(feature = "std")]
@@ -777,7 +797,7 @@ mod test {
777797
use lightning::routing::router::{PaymentParameters, RouteParameters};
778798
use lightning::util::test_utils;
779799
use lightning::util::config::UserConfig;
780-
use crate::utils::create_invoice_from_channelmanager_and_duration_since_epoch;
800+
use crate::utils::{create_invoice_from_channelmanager_and_duration_since_epoch, zip_nested_vectors};
781801
use std::collections::HashSet;
782802

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

0 commit comments

Comments
 (0)