use std::path::Path;
use std::path::PathBuf;
use serde::Deserialize;
use serde::Serialize;
use serde_keyvalue::FromKeyValues;
static VHOST_VSOCK_DEFAULT_PATH: &str = "/dev/vhost-vsock";
fn default_vsock_path() -> PathBuf {
    PathBuf::from(VHOST_VSOCK_DEFAULT_PATH)
}
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, FromKeyValues)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
pub struct VsockConfig {
    pub cid: u64,
    #[serde(default = "default_vsock_path", rename = "device")]
    pub vhost_device: PathBuf,
    #[serde(default)]
    pub max_queue_sizes: Option<[u16; 3]>,
}
impl VsockConfig {
    pub fn new<P: AsRef<Path>>(cid: u64, vhost_device: Option<P>) -> Self {
        Self {
            cid,
            #[cfg(any(target_os = "android", target_os = "linux"))]
            vhost_device: vhost_device
                .map(|p| PathBuf::from(p.as_ref()))
                .unwrap_or_else(|| PathBuf::from(VHOST_VSOCK_DEFAULT_PATH)),
            max_queue_sizes: None,
        }
    }
}
#[cfg(test)]
mod tests {
    use serde_keyvalue::from_key_values;
    use serde_keyvalue::ErrorKind;
    use serde_keyvalue::ParseError;
    use super::*;
    fn from_vsock_arg(options: &str) -> Result<VsockConfig, ParseError> {
        from_key_values(options)
    }
    #[test]
    fn params_from_key_values() {
        assert_eq!(
            from_vsock_arg("cid=56").unwrap(),
            VsockConfig {
                vhost_device: VHOST_VSOCK_DEFAULT_PATH.into(),
                cid: 56,
                max_queue_sizes: None,
            }
        );
        assert_eq!(
            from_vsock_arg("").unwrap_err(),
            ParseError {
                kind: ErrorKind::SerdeError("missing field `cid`".into()),
                pos: 0
            }
        );
        assert_eq!(
            from_vsock_arg("78").unwrap(),
            VsockConfig {
                #[cfg(any(target_os = "android", target_os = "linux"))]
                vhost_device: VHOST_VSOCK_DEFAULT_PATH.into(),
                cid: 78,
                max_queue_sizes: None,
            }
        );
        assert_eq!(
            from_vsock_arg("cid=42,cid=56").unwrap_err(),
            ParseError {
                kind: ErrorKind::SerdeError("duplicate field `cid`".into()),
                pos: 0,
            }
        );
        assert_eq!(
            from_vsock_arg("invalid=foo").unwrap_err(),
            ParseError {
                kind: ErrorKind::SerdeError(
                    "unknown field `invalid`, expected one of `cid`, `device`, `max-queue-sizes`"
                        .into()
                ),
                pos: 0,
            }
        );
        assert_eq!(
            from_vsock_arg("device=/some/path,cid=56").unwrap(),
            VsockConfig {
                vhost_device: "/some/path".into(),
                cid: 56,
                max_queue_sizes: None,
            }
        );
        assert_eq!(
            from_vsock_arg("56,device=/some/path").unwrap(),
            VsockConfig {
                vhost_device: "/some/path".into(),
                cid: 56,
                max_queue_sizes: None,
            }
        );
        assert_eq!(
            from_vsock_arg("device=42").unwrap_err(),
            ParseError {
                kind: ErrorKind::SerdeError("missing field `cid`".into()),
                pos: 0,
            }
        );
        assert_eq!(
            from_vsock_arg("cid=56,device=42,device=/some/path").unwrap_err(),
            ParseError {
                kind: ErrorKind::SerdeError("duplicate field `device`".into()),
                pos: 0,
            }
        );
        assert_eq!(
            from_vsock_arg("cid=56,max-queue-sizes=[1,2,4]").unwrap(),
            VsockConfig {
                vhost_device: VHOST_VSOCK_DEFAULT_PATH.into(),
                cid: 56,
                max_queue_sizes: Some([1, 2, 4]),
            }
        );
    }
}