1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use anyhow::anyhow;
use anyhow::Result;

use crate::bindings;

/// A wrapper over `VAGenericValue` giving us safe access to the underlying union members.
#[derive(Debug)]
pub enum GenericValue {
    /// A wrapper over VAGenericValueTypeInteger
    Integer(i32),
    /// A wrapper over VAGenericValueTypeFloat
    Float(f32),
    /// A wrapper over VAGenericValueTypePointer
    Pointer(*mut std::os::raw::c_void),
    /// A wrapper over VAGenericValueTypeFunc
    Func(bindings::VAGenericFunc),
}

impl TryFrom<bindings::VAGenericValue> for GenericValue {
    type Error = anyhow::Error;

    fn try_from(value: bindings::VAGenericValue) -> Result<Self, Self::Error> {
        // Safe because we check the type before accessing the union.
        match value.type_ {
            // Safe because we check the type before accessing the union.
            bindings::VAGenericValueType::VAGenericValueTypeInteger => {
                Ok(Self::Integer(unsafe { value.value.i }))
            }
            bindings::VAGenericValueType::VAGenericValueTypeFloat => {
                Ok(Self::Float(unsafe { value.value.f }))
            }
            bindings::VAGenericValueType::VAGenericValueTypePointer => {
                Ok(Self::Pointer(unsafe { value.value.p }))
            }
            bindings::VAGenericValueType::VAGenericValueTypeFunc => {
                Ok(Self::Func(unsafe { value.value.fn_ }))
            }
            other => Err(anyhow!(
                "Conversion failed for unexpected VAGenericValueType: {}",
                other
            )),
        }
    }
}