use log::trace;
use secrecy::SecretString;
use thiserror::Error;
use crate::{entry::KeyringEntry, io::KeyringIo};
#[derive(Clone, Debug, Error)]
pub enum WriteSecretError {
#[error("Invalid argument: expected {0}, got {1:?}")]
InvalidArgument(&'static str, KeyringIo),
#[error("Entry and secret not ready")]
NotReady,
}
#[derive(Clone, Debug)]
pub enum WriteSecretResult {
Ok(()),
Io(KeyringIo),
Err(WriteSecretError),
}
#[derive(Clone, Debug)]
pub struct WriteSecret {
secret: Option<(KeyringEntry, SecretString)>,
}
impl WriteSecret {
pub fn new(entry: KeyringEntry, secret: impl Into<SecretString>) -> Self {
let secret = Some((entry, secret.into()));
Self { secret }
}
pub fn resume(&mut self, arg: Option<KeyringIo>) -> WriteSecretResult {
let Some(arg) = arg else {
let Some(secret) = self.secret.take() else {
return WriteSecretResult::Err(WriteSecretError::NotReady);
};
trace!("need I/O to write secret into keyring entry");
return WriteSecretResult::Io(KeyringIo::Write(Err(secret)));
};
let KeyringIo::Write(io) = arg else {
let err = WriteSecretError::InvalidArgument("write output", arg);
return WriteSecretResult::Err(err);
};
if let Err((entry, secret)) = io {
return WriteSecretResult::Io(KeyringIo::Write(Err((entry, secret))));
}
trace!("resume after writing secret into keyring entry");
WriteSecretResult::Ok(())
}
}