Skip to content

Instantly share code, notes, and snippets.

@JohnScience
Created March 2, 2024 01:42
Show Gist options
  • Save JohnScience/b409739f3c84d856e259f9ac56f6c38a to your computer and use it in GitHub Desktop.
Save JohnScience/b409739f3c84d856e259f9ac56f6c38a to your computer and use it in GitHub Desktop.
pub struct VSRegKey(registry::RegKey);
impl VSRegKey {
pub fn open() -> Result<Self, registry::key::Error> {
let regkey = registry::Hive::LocalMachine.open(
r"SOFTWARE\WOW6432Node\Microsoft\VisualStudio",
registry::Security::Read,
)?;
Ok(Self(regkey))
}
pub fn into_inner(self) -> registry::RegKey {
self.0
}
}
/// A version of Visual Studio, e.g. "14.0", "14.29", "15.0", "16.0".
#[derive(Debug)]
pub struct VSVersion(String);
pub struct VCRedistRegKeyForVSVersion(registry::RegKey);
impl VCRedistRegKeyForVSVersion {
pub fn open(version: &VSVersion) -> Result<Self, registry::key::Error> {
let regkey = registry::Hive::LocalMachine.open(
&format!(
r"SOFTWARE\WOW6432Node\Microsoft\VisualStudio\{}\VC\Runtimes\x86",
version.0
),
registry::Security::Read,
)?;
Ok(Self(regkey))
}
pub fn into_inner(self) -> registry::RegKey {
self.0
}
}
/// A generator that yields available versions of Visual Studio and can be used with
/// [`genawaiter::stack::let_gen_using`] macro to create a coroutine-based iterator.
///
/// ## Examples
///
/// ```rust
/// use genawaiter::stack::let_gen_using;
/// use vcredist::{VSRegKey, available_vs_versions_gen};
///
/// fn main() -> Result<(), registry::Error> {
/// let regkey = VSRegKey::open()?;
/// let_gen_using!(gen, |co| async move { available_vs_versions_gen(&regkey, co).await });
/// for version in gen {
/// println!("Found Visual Studio version: {:?}", version);
/// }
/// Ok(())
/// }
/// ```
///
/// Note that in the example above `regkey` gets captured by the closure. In order to mutably borrow or take ownership of `regkey` after the iteration,
/// you have write the code slightly differently.
///
/// The generator must be dropped before the non-shared use of `regkey` and it must capture only the shared reference to the `regkey` instead of the owned value.
///
/// The reason why the generator must be dropped prior to that is that even if it **borrows** the `regkey`, the captured shared reference is dropped in the drop implementation of the generator,
/// which extends the borrow of `regkey` to the end of the scope where the generator is defined.
///
/// ```rust
/// use genawaiter::stack::let_gen_using;
/// use vcredist::{VSRegKey, available_vs_versions_gen};
///
/// fn main() -> Result<(), registry::Error> {
/// let regkey = VSRegKey::open()?;
/// {
/// let regkey_ref = &regkey;
/// let_gen_using!(gen, |co| async move { available_vs_versions_gen(regkey_ref, co).await });
/// for version in gen {
/// println!("Found Visual Studio version: {:?}", version);
/// }
/// }
/// let _inner = regkey.into_inner();
/// Ok(())
/// }
/// ```
///
// TODO: find a way to generalize this function over the couroutine type if genawaiter::core becomes stable/public
pub async fn available_vs_versions_gen(
regkey: &VSRegKey,
co: genawaiter::stack::Co<'_, Result<VSVersion, registry::iter::keys::Error>>,
) {
for subkey in regkey.0.keys() {
let version: Result<String, _> = subkey.map(|k| k.to_string());
let version: String = match version {
Err(e) => {
co.yield_(Err(e)).await;
continue;
}
Ok(v) => v,
};
if version.contains(|c: char| c != '.' && !c.is_numeric()) {
continue;
};
co.yield_(Ok(VSVersion(version))).await;
}
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
use super::{available_vs_versions_gen, VSRegKey};
use genawaiter::stack::let_gen_using;
fn main() -> Result<(), registry::Error> {
let regkey = VSRegKey::open()?;
{
let regkey_ref = &regkey;
let_gen_using!(gen, |co| async move {
available_vs_versions_gen(regkey_ref, co).await
});
for version in gen {
println!("Found Visual Studio version: {:?}", version);
}
}
let _inner = regkey.into_inner();
Ok(())
}
main().unwrap();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment