I'm trying to use the crc-rs crate to hash some files.
There's already a common interface defined. Basically, all "hashers" should implement std::io::Write, so that you can simply do std::io::copy(&mut file, &mut hasher) (like Rust Crypto hashes do). crc-rs, though, uses a "manual" interface like so (from the example using a custom algorithm):
// use custom algorithm
const CUSTOM_ALG: Algorithm<u16> = Algorithm {
    poly: 0x8005,
    init: 0xffff,
    refin: false,
    refout: false,
    xorout: 0x0000,
    check: 0xaee7,
    residue: 0x0000
};
let crc = Crc::<u16>::new(&CUSTOM_ALG);
let mut digest = crc.digest();
digest.update(b"123456789");
assert_eq!(digest.finalize(), 0xaee7);
Notice that you first create a Crc and then you call crc.digest(), which returns a Digest. Internally, a digest seems to contain a reference to the actual Crc that created it, which must live at least as long as the Digest (am I understanding the lifetime correctly?).
So, basically, I want to create an encapsulated struct that contains its own Crc and the Digest it generates. Then, I can implement std::io::Write over this struct (similar to this). Something along these lines:
pub struct CRC32Hasher<'a> {
    crc: crc::Crc<u32>,
    crc_digest: crc::Digest<'a, u32>,
}
impl<'a> CRC32Hasher<'a> { // Is the lifetime being used properly here?
    pub fn new() -> CRC32Hasher<'a> {
        let crc = crc::Crc::<u32>::new(&crc::CRC_32_CKSUM);
        let result = CRC32Hasher{
            crc_digest: crc.digest(),
            crc,
        };
        result
    }
}
cargo check output:
error[E0505]: cannot move out of `crc` because it is borrowed
  --> src\hash.rs:20:4
   |
14 | impl<'a> CRC32Hasher<'a> { // Is the lifetime being used properly here?
   |      -- lifetime `'a` defined here
...
19 |             crc_digest: crc.digest(),
   |                         ------------ borrow of `crc` occurs here
20 |             crc,
   |             ^^^ move out of `crc` occurs here
...
23 |         result
   |         ------ returning this value requires that `crc` is borrowed for `'a`
error[E0515]: cannot return value referencing local variable `crc`
  --> src\hash.rs:23:3
   |
19 |             crc_digest: crc.digest(),
   |                         ------------ `crc` is borrowed here
...
23 |         result
   |         ^^^^^^ returns a value referencing data owned by the current function
Some errors have detailed explanations: E0505, E0515.
For more information about an error, try `rustc --explain E0505`.
error: could not compile `hasher` due to 2 previous errors
I'm afraid I'm very new to Rust (this is sort of a test project). I still don't quite get how lifetime generics work in practice, for example. I don't know how to start tackling this problem. Is there a standard way to deal with this kind of pattern? Similar problems with self-referential data led me to believe I need unsafe code, or at least std::ptr and std::pin::Pin? Am I way overthinking this?
I could of course simply change the interface or use another CRC implementation, but I got interested in the general problem. I would like to know what's the good practice in this kind of situation.
Edit:
I had came into this and similar. I think I understand the logic on why the problem happens (that post in particular helped me a lot). I also think I could fix it if crc_digest was a simple reference to data directly in the struct; the official Pin tutorial and every other I've found seems to assume this case. I think (and this may be just my inexperience) this is different because I'm not directly referencing data in the struct. I'm creating a new piece of data (the Digest), which happens to reference my data, and then I need to point to that. I don't know what needs to change to do this safely.
