1use std::fmt::{Debug, Display, Write};
2
3use anyhow::{bail, Result};
4use log::*;
5use reqwest::Response;
6use serde::Deserialize;
7
8use crate::Consul;
9
10impl Consul {
11 pub(crate) async fn get_with_index<T: for<'de> Deserialize<'de>>(
12 &self,
13 mut url: String,
14 last_index: Option<usize>,
15 ) -> Result<WithIndex<T>> {
16 if let Some(i) = last_index {
17 if url.contains('?') {
18 write!(&mut url, "&index={}", i).unwrap();
19 } else {
20 write!(&mut url, "?index={}", i).unwrap();
21 }
22 }
23 debug!("GET {} as {}", url, std::any::type_name::<T>());
24
25 let http = self.client.get(&url).send().await?;
26
27 Ok(WithIndex::<T>::index_from(&http)?.value(http.json().await?))
28 }
29}
30
31pub struct WithIndex<T> {
35 pub(crate) value: T,
36 pub(crate) index: usize,
37}
38
39impl<T> WithIndex<T> {
40 pub fn index_from(resp: &Response) -> Result<WithIndexBuilder<T>> {
42 let index = match resp.headers().get("X-Consul-Index") {
43 Some(v) => v.to_str()?.parse::<usize>()?,
44 None => bail!("X-Consul-Index header not found"),
45 };
46 Ok(WithIndexBuilder {
47 index,
48 _phantom: Default::default(),
49 })
50 }
51
52 pub fn into_inner(self) -> T {
54 self.value
55 }
56
57 pub fn index(&self) -> usize {
60 self.index
61 }
62}
63
64impl<T> std::convert::AsRef<T> for WithIndex<T> {
65 fn as_ref(&self) -> &T {
66 &self.value
67 }
68}
69
70impl<T> std::borrow::Borrow<T> for WithIndex<T> {
71 fn borrow(&self) -> &T {
72 &self.value
73 }
74}
75
76impl<T> std::ops::Deref for WithIndex<T> {
77 type Target = T;
78 fn deref(&self) -> &T {
79 &self.value
80 }
81}
82
83impl<T: Debug> Debug for WithIndex<T> {
84 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 <T as Debug>::fmt(self, f)
86 }
87}
88
89impl<T: Display> Display for WithIndex<T> {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91 <T as Display>::fmt(self, f)
92 }
93}
94
95pub struct WithIndexBuilder<T> {
97 _phantom: std::marker::PhantomData<T>,
98 index: usize,
99}
100
101impl<T> WithIndexBuilder<T> {
102 pub fn value(self, value: T) -> WithIndex<T> {
104 WithIndex {
105 value,
106 index: self.index,
107 }
108 }
109}