1#[cfg(feature = "async")]
41pub mod async_digest;
42#[cfg(feature = "native_openssl")]
43mod openssl_sha256;
44
45#[cfg(feature = "native_openssl")]
46use crate::openssl_sha256::OpenSslSha256;
47
48#[cfg(feature = "async")]
49pub use async_digest::*;
50
51use sha2::digest::Output;
52use sha2::{Digest, Sha256};
53use std::fmt::Debug;
54use std::fs;
55use std::io;
56use std::io::{BufReader, Read};
57use std::path::Path;
58
59#[cfg(test)]
60mod tests;
61
62pub fn digest<D: Sha256Digest>(input: D) -> String {
74 input.digest()
75}
76
77pub fn try_digest<D: TrySha256Digest>(input: D) -> Result<String, D::Error> {
89 input.digest()
90}
91
92#[deprecated(since = "1.1.0", note = "Use new function `digest()` instead")]
104pub fn digest_bytes(input: &[u8]) -> String {
105 __digest__(input)
106}
107
108#[deprecated(since = "1.1.0", note = "Use new function `try_digest()` instead")]
120pub fn digest_file<P: AsRef<Path>>(path: P) -> Result<String, io::Error> {
121 let bytes = fs::read(path)?;
122 Ok(__digest__(&bytes))
123}
124
125pub trait Sha256Digest {
126 fn digest(self) -> String;
127}
128
129#[async_trait::async_trait]
130pub trait TrySha256Digest {
131 type Error: Debug;
132
133 fn digest(self) -> Result<String, Self::Error>;
134
135 #[cfg(feature = "async")]
136 async fn async_digest(self) -> Result<String, Self::Error>;
137
138 #[cfg(feature = "native_openssl")]
139 async fn async_openssl_digest(self) -> Result<String, Self::Error>;
140}
141
142impl<const N: usize> Sha256Digest for &[u8; N] {
143 fn digest(self) -> String {
144 __digest__(self)
145 }
146}
147
148impl Sha256Digest for &[u8] {
149 fn digest(self) -> String {
150 __digest__(self)
151 }
152}
153
154impl Sha256Digest for &Vec<u8> {
155 fn digest(self) -> String {
156 __digest__(self)
157 }
158}
159
160impl Sha256Digest for Vec<u8> {
161 fn digest(self) -> String {
162 __digest__(&self)
163 }
164}
165
166impl Sha256Digest for String {
167 fn digest(self) -> String {
168 __digest__(self.as_bytes())
169 }
170}
171
172impl Sha256Digest for &str {
173 fn digest(self) -> String {
174 __digest__(self.as_bytes())
175 }
176}
177
178impl Sha256Digest for char {
179 fn digest(self) -> String {
180 __digest__(self.encode_utf8(&mut [0; 4]).as_bytes())
181 }
182}
183
184impl Sha256Digest for &mut &str {
185 fn digest(self) -> String {
186 __digest__(self.as_bytes())
187 }
188}
189
190impl Sha256Digest for &String {
191 fn digest(self) -> String {
192 __digest__(self.as_bytes())
193 }
194}
195
196#[async_trait::async_trait]
197impl<P> TrySha256Digest for P
198where
199 P: AsRef<Path> + Send,
200{
201 type Error = io::Error;
202
203 fn digest(self) -> Result<String, Self::Error> {
204 let f = fs::File::open(self)?;
205 let reader = BufReader::new(f);
206 let sha = Sha256::new();
207 calc(reader, sha)
208 }
209
210 #[cfg(feature = "async")]
211 async fn async_digest(self) -> Result<String, Self::Error> {
212 let f = tokio::fs::File::open(self).await?;
213 let reader = tokio::io::BufReader::new(f);
214 let sha = Sha256::new();
215 async_calc(reader, sha).await
216 }
217
218 #[cfg(all(feature = "async", feature = "native_openssl"))]
219 async fn async_openssl_digest(self) -> Result<String, Self::Error> {
220 let f = tokio::fs::File::open(self).await?;
221 let reader = tokio::io::BufReader::new(f);
222 let sha = OpenSslSha256::new();
223 async_calc(reader, sha).await
224 }
225}
226
227fn __digest__(data: &[u8]) -> String {
228 hex::encode(Sha256::digest(data))
229}
230
231trait CalculatorInput {
232 fn read_inner(&mut self, buf: &mut [u8]) -> std::io::Result<usize>;
233}
234
235impl<T> CalculatorInput for T
236where
237 T: Read,
238{
239 fn read_inner(&mut self, buf: &mut [u8]) -> io::Result<usize> {
240 self.read(buf)
241 }
242}
243
244pub trait CalculatorSelector {
245 type FinishType: AsRef<[u8]>;
246 fn update_inner(&mut self, data: &[u8]);
247 fn finish_inner(self) -> Self::FinishType;
248}
249
250impl CalculatorSelector for Sha256 {
251 type FinishType = Output<Sha256>;
252
253 fn update_inner(&mut self, data: &[u8]) {
254 self.update(data)
255 }
256
257 fn finish_inner(self) -> Self::FinishType {
258 self.finalize()
259 }
260}
261
262fn calc<I, S>(mut input: I, mut selector: S) -> io::Result<String>
263where
264 I: CalculatorInput,
265 S: CalculatorSelector,
266{
267 let mut buf = [0u8; 1024];
268 loop {
269 let len = input.read_inner(&mut buf)?;
270 if len == 0 {
271 break;
272 }
273 selector.update_inner(&buf[0..len]);
274 }
275 let hash = selector.finish_inner();
276 Ok(hex::encode(hash))
277}