<commit_before>//! Shared types used in tealdeer.

use std::{fmt, str};

use anyhow::{anyhow, Result};
use serde_derive::{Deserialize, Serialize};

#[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[allow(dead_code)]
pub enum PlatformType {
    Linux,
    OsX,
    SunOs,
    Windows,
    Android,
}

impl fmt::Display for PlatformType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Self::Linux => write!(f, "Linux"),
            Self::OsX => write!(f, "macOS / BSD"),
            Self::SunOs => write!(f, "SunOS"),
            Self::Windows => write!(f, "Windows"),
            Self::Android => write!(f, "Android"),
        }
    }
}

impl str::FromStr for PlatformType {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "linux" => Ok(Self::Linux),
            "osx" | "macos" => Ok(Self::OsX),
            "sunos" => Ok(Self::SunOs),
            "windows" => Ok(Self::Windows),
            "android" => Ok(Self::Android),
            other => Err(anyhow!(
                "Unknown OS: {}. Possible values: linux, macos, osx, sunos, windows, android",
                other
            )),
        }
    }
}

impl PlatformType {
    #[cfg(target_os = "linux")]
    pub fn current() -> Self {
        Self::Linux
    }

    #[cfg(any(
        target_os = "macos",
        target_os = "freebsd",
        target_os = "netbsd",
        target_os = "openbsd",
        target_os = "dragonfly"
    ))]
    pub fn current() -> Self {
        Self::OsX
    }

    #[cfg(target_os = "windows")]
    pub fn current() -> Self {
        Self::Windows
    }

    #[cfg(not(any(
        target_os = "linux",
        target_os = "macos",
        target_os = "freebsd",
        target_os = "netbsd",
        target_os = "openbsd",
        target_os = "dragonfly",
        target_os = "windows"
    )))]
    pub fn current() -> Self {
        Self::Other
    }
}

#[derive(Debug, Eq, PartialEq, Copy, Clone, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ColorOptions {
    Always,
    Auto,
    Never,
}

impl str::FromStr for ColorOptions {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self> {
        match s {
            "always" => Ok(Self::Always),
            "auto" => Ok(Self::Auto),
            "never" => Ok(Self::Never),
            other => Err(anyhow!(
                "Unknown color option: {}. Possible values: always, auto, never",
                other
            )),
        }
    }
}

impl Default for ColorOptions {
    fn default() -> Self {
        Self::Auto
    }
}

#[derive(Debug, Eq, PartialEq)]
pub enum LineType {
    Empty,
    Title(String),
    Description(String),
    ExampleText(String),
    ExampleCode(String),
    Other(String),
}

impl<'a> From<&'a str> for LineType {
    /// Convert a string slice to a `LineType`. Newlines and trailing whitespace are trimmed.
    fn from(line: &'a str) -> Self {
        let trimmed: &str = line.trim_end();
        let mut chars = trimmed.chars();
        match chars.next() {
            None => Self::Empty,
            Some('#') => Self::Title(
                trimmed
                    .trim_start_matches(|chr: char| chr == '#' || chr.is_whitespace())
                    .into(),
            ),
            Some('>') => Self::Description(
                trimmed
                    .trim_start_matches(|chr: char| chr == '>' || chr.is_whitespace())
                    .into(),
            ),
            Some(' ') => Self::ExampleCode(trimmed.trim_start_matches(char::is_whitespace).into()),
            Some(_) => Self::ExampleText(trimmed.into()),
        }
    }
}

impl LineType {
    /// Support for old format.
    /// TODO: Remove once old format has been phased out!
    pub fn from_v1(line: &str) -> Self {
        let trimmed = line.trim();
        let mut chars = trimmed.chars();
        match chars.next() {
            None => Self::Empty,
            Some('#') => Self::Title(
                trimmed
                    .trim_start_matches(|chr: char| chr == '#' || chr.is_whitespace())
                    .into(),
            ),
            Some('>') => Self::Description(
                trimmed
                    .trim_start_matches(|chr: char| chr == '>' || chr.is_whitespace())
                    .into(),
            ),
            Some('-') => Self::ExampleText(
                trimmed
                    .trim_start_matches(|chr: char| chr == '-' || chr.is_whitespace())
                    .into(),
            ),
            Some('`') if chars.last() == Some('`') => Self::ExampleCode(
                trimmed
                    .trim_matches(|chr: char| chr == '`' || chr.is_whitespace())
                    .into(),
            ),
            Some(_) => Self::Other(trimmed.into()),
        }
    }
}

/// The reason why a certain path (e.g. config path or cache dir) was chosen.
#[derive(Debug, PartialEq)]
pub enum PathSource {
    /// OS convention (e.g. XDG on Linux)
    OsConvention,
    /// Env variable (TEALDEER_*)
    EnvVar,

    #[allow(dead_code)] // Waiting for Pull Request #141
    /// Config file variable
    ConfigVar,
}

impl fmt::Display for PathSource {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "{}",
            match self {
                Self::OsConvention => "OS convention",
                Self::EnvVar => "env variable",
                Self::ConfigVar => "config file variable",
            }
        )
    }
}

#[cfg(test)]
mod test {
    use super::LineType;

    #[test]
    fn test_linetype_from_str() {
        assert_eq!(LineType::from(""), LineType::Empty);
        assert_eq!(LineType::from(" \n \r"), LineType::Empty);
        assert_eq!(
            LineType::from("# Hello there"),
            LineType::Title("Hello there".into())
        );
        assert_eq!(
            LineType::from("> tis a description \n"),
            LineType::Description("tis a description".into())
        );
        assert_eq!(
            LineType::from("some command "),
            LineType::ExampleText("some command".into())
        );
        assert_eq!(
            LineType::from("    $ cargo run "),
            LineType::ExampleCode("$ cargo run".into())
        );
    }
}
<commit_msg>Add PlatformType::current for android target<commit_after>//! Shared types used in tealdeer.

use std::{fmt, str};

use anyhow::{anyhow, Result};
use serde_derive::{Deserialize, Serialize};

#[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[allow(dead_code)]
pub enum PlatformType {
    Linux,
    OsX,
    SunOs,
    Windows,
    Android,
}

impl fmt::Display for PlatformType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Self::Linux => write!(f, "Linux"),
            Self::OsX => write!(f, "macOS / BSD"),
            Self::SunOs => write!(f, "SunOS"),
            Self::Windows => write!(f, "Windows"),
            Self::Android => write!(f, "Android"),
        }
    }
}

impl str::FromStr for PlatformType {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "linux" => Ok(Self::Linux),
            "osx" | "macos" => Ok(Self::OsX),
            "sunos" => Ok(Self::SunOs),
            "windows" => Ok(Self::Windows),
            "android" => Ok(Self::Android),
            other => Err(anyhow!(
                "Unknown OS: {}. Possible values: linux, macos, osx, sunos, windows, android",
                other
            )),
        }
    }
}

impl PlatformType {
    #[cfg(target_os = "linux")]
    pub fn current() -> Self {
        Self::Linux
    }

    #[cfg(any(
        target_os = "macos",
        target_os = "freebsd",
        target_os = "netbsd",
        target_os = "openbsd",
        target_os = "dragonfly"
    ))]
    pub fn current() -> Self {
        Self::OsX
    }

    #[cfg(target_os = "windows")]
    pub fn current() -> Self {
        Self::Windows
    }

    #[cfg(target_os = "android")]
    pub fn current() -> Self {
        Self::Android
    }

    #[cfg(not(any(
        target_os = "linux",
        target_os = "macos",
        target_os = "freebsd",
        target_os = "netbsd",
        target_os = "openbsd",
        target_os = "dragonfly",
        target_os = "windows",
        target_os = "android",
    )))]
    pub fn current() -> Self {
        Self::Other
    }
}

#[derive(Debug, Eq, PartialEq, Copy, Clone, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ColorOptions {
    Always,
    Auto,
    Never,
}

impl str::FromStr for ColorOptions {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self> {
        match s {
            "always" => Ok(Self::Always),
            "auto" => Ok(Self::Auto),
            "never" => Ok(Self::Never),
            other => Err(anyhow!(
                "Unknown color option: {}. Possible values: always, auto, never",
                other
            )),
        }
    }
}

impl Default for ColorOptions {
    fn default() -> Self {
        Self::Auto
    }
}

#[derive(Debug, Eq, PartialEq)]
pub enum LineType {
    Empty,
    Title(String),
    Description(String),
    ExampleText(String),
    ExampleCode(String),
    Other(String),
}

impl<'a> From<&'a str> for LineType {
    /// Convert a string slice to a `LineType`. Newlines and trailing whitespace are trimmed.
    fn from(line: &'a str) -> Self {
        let trimmed: &str = line.trim_end();
        let mut chars = trimmed.chars();
        match chars.next() {
            None => Self::Empty,
            Some('#') => Self::Title(
                trimmed
                    .trim_start_matches(|chr: char| chr == '#' || chr.is_whitespace())
                    .into(),
            ),
            Some('>') => Self::Description(
                trimmed
                    .trim_start_matches(|chr: char| chr == '>' || chr.is_whitespace())
                    .into(),
            ),
            Some(' ') => Self::ExampleCode(trimmed.trim_start_matches(char::is_whitespace).into()),
            Some(_) => Self::ExampleText(trimmed.into()),
        }
    }
}

impl LineType {
    /// Support for old format.
    /// TODO: Remove once old format has been phased out!
    pub fn from_v1(line: &str) -> Self {
        let trimmed = line.trim();
        let mut chars = trimmed.chars();
        match chars.next() {
            None => Self::Empty,
            Some('#') => Self::Title(
                trimmed
                    .trim_start_matches(|chr: char| chr == '#' || chr.is_whitespace())
                    .into(),
            ),
            Some('>') => Self::Description(
                trimmed
                    .trim_start_matches(|chr: char| chr == '>' || chr.is_whitespace())
                    .into(),
            ),
            Some('-') => Self::ExampleText(
                trimmed
                    .trim_start_matches(|chr: char| chr == '-' || chr.is_whitespace())
                    .into(),
            ),
            Some('`') if chars.last() == Some('`') => Self::ExampleCode(
                trimmed
                    .trim_matches(|chr: char| chr == '`' || chr.is_whitespace())
                    .into(),
            ),
            Some(_) => Self::Other(trimmed.into()),
        }
    }
}

/// The reason why a certain path (e.g. config path or cache dir) was chosen.
#[derive(Debug, PartialEq)]
pub enum PathSource {
    /// OS convention (e.g. XDG on Linux)
    OsConvention,
    /// Env variable (TEALDEER_*)
    EnvVar,

    #[allow(dead_code)] // Waiting for Pull Request #141
    /// Config file variable
    ConfigVar,
}

impl fmt::Display for PathSource {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "{}",
            match self {
                Self::OsConvention => "OS convention",
                Self::EnvVar => "env variable",
                Self::ConfigVar => "config file variable",
            }
        )
    }
}

#[cfg(test)]
mod test {
    use super::LineType;

    #[test]
    fn test_linetype_from_str() {
        assert_eq!(LineType::from(""), LineType::Empty);
        assert_eq!(LineType::from(" \n \r"), LineType::Empty);
        assert_eq!(
            LineType::from("# Hello there"),
            LineType::Title("Hello there".into())
        );
        assert_eq!(
            LineType::from("> tis a description \n"),
            LineType::Description("tis a description".into())
        );
        assert_eq!(
            LineType::from("some command "),
            LineType::ExampleText("some command".into())
        );
        assert_eq!(
            LineType::from("    $ cargo run "),
            LineType::ExampleCode("$ cargo run".into())
        );
    }
}
<|endoftext|>


<commit_before>extern mod extra;

use extra::json;
use extra::json::Json;
use extra::uuid::Uuid;
use std::rt::io::Decorator;
use std::rt::io::extensions::{WriterByteConversions, ReaderByteConversions};
use std::rt::io::mem::{MemWriter, BufReader};
use std::str;

pub type Oid = i32;

// Values from pg_type.h
static BOOLOID: Oid = 16;
static BYTEAOID: Oid = 17;
static CHAROID: Oid = 18;
static INT8OID: Oid = 20;
static INT2OID: Oid = 21;
static INT4OID: Oid = 23;
static TEXTOID: Oid = 25;
static JSONOID: Oid = 114;
static FLOAT4OID: Oid = 700;
static FLOAT8OID: Oid = 701;
static BPCHAROID: Oid = 1042;
static VARCHAROID: Oid = 1043;
static UUIDOID: Oid = 2950;

pub enum PostgresType {
    PgBool,
    PgByteA,
    PgChar,
    PgInt8,
    PgInt2,
    PgInt4,
    PgText,
    PgJson,
    PgFloat4,
    PgFloat8,
    PgCharN,
    PgVarchar,
    PgUuid,
    PgUnknownType(Oid)
}

impl PostgresType {
    pub fn from_oid(oid: Oid) -> PostgresType {
        match oid {
            BOOLOID => PgBool,
            BYTEAOID => PgByteA,
            CHAROID => PgChar,
            INT8OID => PgInt8,
            INT2OID => PgInt2,
            INT4OID => PgInt4,
            TEXTOID => PgText,
            JSONOID => PgJson,
            FLOAT4OID => PgFloat4,
            FLOAT8OID => PgFloat8,
            BPCHAROID => PgCharN,
            VARCHAROID => PgVarchar,
            UUIDOID => PgUuid,
            oid => PgUnknownType(oid)
        }
    }

    pub fn result_format(&self) -> Format {
        match *self {
            PgBool
            | PgByteA
            | PgInt8
            | PgInt2
            | PgInt4
            | PgFloat4
            | PgFloat8
            | PgUuid => Binary,
            _ => Text
        }
    }
}

pub enum Format {
    Text = 0,
    Binary = 1
}

macro_rules! check_oid(
    ($($expected:ident)|+, $actual:ident) => (
        match $actual {
            $($expected)|+ => (),
            actual => fail!("Invalid Oid %?", actual)
        }
    )
)

pub trait FromSql {
    fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> Self;
}

macro_rules! from_map_impl(
    ($($oid:ident)|+, $t:ty, $blk:expr) => (
        impl FromSql for Option<$t> {
            fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> Option<$t> {
                check_oid!($($oid)|+, ty)
                raw.map($blk)
            }
        }
    )
)

macro_rules! from_conversions_impl(
    ($oid:ident, $t:ty, $f:ident) => (
        from_map_impl!($oid, $t, |buf| {
            let mut reader = BufReader::new(buf.as_slice());
            reader.$f()
        })
    )
)

macro_rules! from_option_impl(
    ($t:ty) => (
        impl FromSql for $t {
            fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> $t {
                // FIXME when you can specify Self types properly
                let ret: Option<$t> = FromSql::from_sql(ty, raw);
                ret.unwrap()
            }
        }
    )
)

from_map_impl!(PgBool, bool, |buf| { buf[0] != 0 })
from_option_impl!(bool)

from_conversions_impl!(PgChar, i8, read_i8_)
from_option_impl!(i8)
from_conversions_impl!(PgInt2, i16, read_be_i16_)
from_option_impl!(i16)
from_conversions_impl!(PgInt4, i32, read_be_i32_)
from_option_impl!(i32)
from_conversions_impl!(PgInt8, i64, read_be_i64_)
from_option_impl!(i64)
from_conversions_impl!(PgFloat4, f32, read_be_f32_)
from_option_impl!(f32)
from_conversions_impl!(PgFloat8, f64, read_be_f64_)
from_option_impl!(f64)

from_map_impl!(PgVarchar | PgText | PgCharN, ~str, |buf| {
    str::from_bytes(buf.as_slice())
})
from_option_impl!(~str)

impl FromSql for Option<~[u8]> {
    fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> Option<~[u8]> {
        check_oid!(PgByteA, ty)
        raw.clone()
    }
}
from_option_impl!(~[u8])

from_map_impl!(PgJson, Json, |buf| {
    json::from_str(str::from_bytes_slice(buf.as_slice())).unwrap()
})
from_option_impl!(Json)

from_map_impl!(PgUuid, Uuid, |buf| {
    Uuid::from_bytes(buf.as_slice()).unwrap()
})
from_option_impl!(Uuid)

pub trait ToSql {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>);
}

macro_rules! to_option_impl(
    ($($oid:ident)|+, $t:ty) => (
        impl ToSql for Option<$t> {
            fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
                check_oid!($($oid)|+, ty)

                match *self {
                    None => (Text, None),
                    Some(ref val) => val.to_sql(ty)
                }
            }
        }
    );
    (self, $($oid:ident)|+, $t:ty) => (
        impl<'self> ToSql for Option<$t> {
            fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
                check_oid!($($oid)|+, ty)

                match *self {
                    None => (Text, None),
                    Some(ref val) => val.to_sql(ty)
                }
            }
        }
    )
)

macro_rules! to_conversions_impl(
    ($($oid:ident)|+, $t:ty, $f:ident) => (
        impl ToSql for $t {
            fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
                check_oid!($($oid)|+, ty)

                let mut writer = MemWriter::new();
                writer.$f(*self);
                (Binary, Some(writer.inner()))
            }
        }
    )
)

impl ToSql for bool {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_oid!(PgBool, ty)
        (Binary, Some(~[*self as u8]))
    }
}
to_option_impl!(PgBool, bool)

to_conversions_impl!(PgChar, i8, write_i8_)
to_option_impl!(PgChar, i8)
to_conversions_impl!(PgInt2, i16, write_be_i16_)
to_option_impl!(PgInt2, i16)
to_conversions_impl!(PgInt4, i32, write_be_i32_)
to_option_impl!(PgInt4, i32)
to_conversions_impl!(PgInt8, i64, write_be_i64_)
to_option_impl!(PgInt8, i64)
to_conversions_impl!(PgFloat4, f32, write_be_f32_)
to_option_impl!(PgFloat4, f32)
to_conversions_impl!(PgFloat8, f64, write_be_f64_)
to_option_impl!(PgFloat8, f64)

impl ToSql for ~str {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_oid!(PgVarchar | PgText | PgCharN, ty)
        (Text, Some(self.as_bytes().to_owned()))
    }
}

impl<'self> ToSql for &'self str {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_oid!(PgVarchar | PgText | PgCharN, ty)
        (Text, Some(self.as_bytes().to_owned()))
    }
}

to_option_impl!(PgVarchar | PgText | PgCharN, ~str)
to_option_impl!(self, PgVarchar | PgText | PgCharN, &'self str)

impl ToSql for ~[u8] {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_oid!(PgByteA, ty)
        (Binary, Some(self.to_owned()))
    }
}

impl<'self> ToSql for &'self [u8] {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_oid!(PgByteA, ty)
        (Binary, Some(self.to_owned()))
    }
}

to_option_impl!(PgByteA, ~[u8])
to_option_impl!(self, PgByteA, &'self [u8])

impl ToSql for Json {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_oid!(PgJson, ty)
        (Text, Some(self.to_str().into_bytes()))
    }
}

to_option_impl!(PgJson, Json)

impl ToSql for Uuid {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_oid!(PgUuid, ty)
        (Binary, Some(self.to_bytes().to_owned()))
    }
}

to_option_impl!(PgUuid, Uuid)
<commit_msg>Types cleanup<commit_after>extern mod extra;

use extra::json;
use extra::json::Json;
use extra::uuid::Uuid;
use std::rt::io::Decorator;
use std::rt::io::extensions::{WriterByteConversions, ReaderByteConversions};
use std::rt::io::mem::{MemWriter, BufReader};
use std::str;

pub type Oid = i32;

// Values from pg_type.h
static BOOLOID: Oid = 16;
static BYTEAOID: Oid = 17;
static CHAROID: Oid = 18;
static INT8OID: Oid = 20;
static INT2OID: Oid = 21;
static INT4OID: Oid = 23;
static TEXTOID: Oid = 25;
static JSONOID: Oid = 114;
static FLOAT4OID: Oid = 700;
static FLOAT8OID: Oid = 701;
static BPCHAROID: Oid = 1042;
static VARCHAROID: Oid = 1043;
static UUIDOID: Oid = 2950;

pub enum PostgresType {
    PgBool,
    PgByteA,
    PgChar,
    PgInt8,
    PgInt2,
    PgInt4,
    PgText,
    PgJson,
    PgFloat4,
    PgFloat8,
    PgCharN,
    PgVarchar,
    PgUuid,
    PgUnknownType(Oid)
}

impl PostgresType {
    pub fn from_oid(oid: Oid) -> PostgresType {
        match oid {
            BOOLOID => PgBool,
            BYTEAOID => PgByteA,
            CHAROID => PgChar,
            INT8OID => PgInt8,
            INT2OID => PgInt2,
            INT4OID => PgInt4,
            TEXTOID => PgText,
            JSONOID => PgJson,
            FLOAT4OID => PgFloat4,
            FLOAT8OID => PgFloat8,
            BPCHAROID => PgCharN,
            VARCHAROID => PgVarchar,
            UUIDOID => PgUuid,
            oid => PgUnknownType(oid)
        }
    }

    pub fn result_format(&self) -> Format {
        match *self {
            PgBool
            | PgByteA
            | PgInt8
            | PgInt2
            | PgInt4
            | PgFloat4
            | PgFloat8
            | PgUuid => Binary,
            _ => Text
        }
    }
}

pub enum Format {
    Text = 0,
    Binary = 1
}

macro_rules! check_types(
    ($($expected:pat)|+, $actual:ident) => (
        match $actual {
            $($expected)|+ => (),
            actual => fail2!("Invalid Postgres type {:?}", actual)
        }
    )
)

pub trait FromSql {
    fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> Self;
}

macro_rules! from_map_impl(
    ($($expected:pat)|+, $t:ty, $blk:expr) => (
        impl FromSql for Option<$t> {
            fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> Option<$t> {
                check_types!($($expected)|+, ty)
                raw.map($blk)
            }
        }
    )
)

macro_rules! from_conversions_impl(
    ($expected:pat, $t:ty, $f:ident) => (
        from_map_impl!($expected, $t, |buf| {
            let mut reader = BufReader::new(buf.as_slice());
            reader.$f()
        })
    )
)

macro_rules! from_option_impl(
    ($t:ty) => (
        impl FromSql for $t {
            fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> $t {
                // FIXME when you can specify Self types properly
                let ret: Option<$t> = FromSql::from_sql(ty, raw);
                ret.unwrap()
            }
        }
    )
)

from_map_impl!(PgBool, bool, |buf| { buf[0] != 0 })
from_option_impl!(bool)

from_conversions_impl!(PgChar, i8, read_i8_)
from_option_impl!(i8)
from_conversions_impl!(PgInt2, i16, read_be_i16_)
from_option_impl!(i16)
from_conversions_impl!(PgInt4, i32, read_be_i32_)
from_option_impl!(i32)
from_conversions_impl!(PgInt8, i64, read_be_i64_)
from_option_impl!(i64)
from_conversions_impl!(PgFloat4, f32, read_be_f32_)
from_option_impl!(f32)
from_conversions_impl!(PgFloat8, f64, read_be_f64_)
from_option_impl!(f64)

from_map_impl!(PgVarchar | PgText | PgCharN, ~str, |buf| {
    str::from_bytes(buf.as_slice())
})
from_option_impl!(~str)

impl FromSql for Option<~[u8]> {
    fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> Option<~[u8]> {
        check_types!(PgByteA, ty)
        raw.clone()
    }
}
from_option_impl!(~[u8])

from_map_impl!(PgJson, Json, |buf| {
    json::from_str(str::from_bytes_slice(buf.as_slice())).unwrap()
})
from_option_impl!(Json)

from_map_impl!(PgUuid, Uuid, |buf| {
    Uuid::from_bytes(buf.as_slice()).unwrap()
})
from_option_impl!(Uuid)

pub trait ToSql {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>);
}

macro_rules! to_option_impl(
    ($($oid:ident)|+, $t:ty) => (
        impl ToSql for Option<$t> {
            fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
                check_types!($($oid)|+, ty)

                match *self {
                    None => (Text, None),
                    Some(ref val) => val.to_sql(ty)
                }
            }
        }
    );
    (self, $($oid:ident)|+, $t:ty) => (
        impl<'self> ToSql for Option<$t> {
            fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
                check_types!($($oid)|+, ty)

                match *self {
                    None => (Text, None),
                    Some(ref val) => val.to_sql(ty)
                }
            }
        }
    )
)

macro_rules! to_conversions_impl(
    ($($oid:ident)|+, $t:ty, $f:ident) => (
        impl ToSql for $t {
            fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
                check_types!($($oid)|+, ty)

                let mut writer = MemWriter::new();
                writer.$f(*self);
                (Binary, Some(writer.inner()))
            }
        }
    )
)

impl ToSql for bool {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_types!(PgBool, ty)
        (Binary, Some(~[*self as u8]))
    }
}
to_option_impl!(PgBool, bool)

to_conversions_impl!(PgChar, i8, write_i8_)
to_option_impl!(PgChar, i8)
to_conversions_impl!(PgInt2, i16, write_be_i16_)
to_option_impl!(PgInt2, i16)
to_conversions_impl!(PgInt4, i32, write_be_i32_)
to_option_impl!(PgInt4, i32)
to_conversions_impl!(PgInt8, i64, write_be_i64_)
to_option_impl!(PgInt8, i64)
to_conversions_impl!(PgFloat4, f32, write_be_f32_)
to_option_impl!(PgFloat4, f32)
to_conversions_impl!(PgFloat8, f64, write_be_f64_)
to_option_impl!(PgFloat8, f64)

impl ToSql for ~str {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_types!(PgVarchar | PgText | PgCharN, ty)
        (Text, Some(self.as_bytes().to_owned()))
    }
}

impl<'self> ToSql for &'self str {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_types!(PgVarchar | PgText | PgCharN, ty)
        (Text, Some(self.as_bytes().to_owned()))
    }
}

to_option_impl!(PgVarchar | PgText | PgCharN, ~str)
to_option_impl!(self, PgVarchar | PgText | PgCharN, &'self str)

impl ToSql for ~[u8] {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_types!(PgByteA, ty)
        (Binary, Some(self.to_owned()))
    }
}

impl<'self> ToSql for &'self [u8] {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_types!(PgByteA, ty)
        (Binary, Some(self.to_owned()))
    }
}

to_option_impl!(PgByteA, ~[u8])
to_option_impl!(self, PgByteA, &'self [u8])

impl ToSql for Json {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_types!(PgJson, ty)
        (Text, Some(self.to_str().into_bytes()))
    }
}

to_option_impl!(PgJson, Json)

impl ToSql for Uuid {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_types!(PgUuid, ty)
        (Binary, Some(self.to_bytes().to_owned()))
    }
}

to_option_impl!(PgUuid, Uuid)
<|endoftext|>


<commit_before>#![crate_name = "sam4l"]
#![crate_type = "rlib"]
#![feature(asm,core,concat_idents,no_std)]
#![no_std]

extern crate core;
extern crate common;
extern crate hil;

pub fn volatile_load<T>(item: &T) -> T {
    unsafe {
        core::intrinsics::volatile_load(item)
    }
}

pub fn volatile_store<T>(item: &mut T, val: T) {
    unsafe {
        core::intrinsics::volatile_store(item, val)
    }
}

macro_rules! volatile {
    ($item:expr) => ({
        ::volatile_load(&$item)
    });

    ($item:ident = $value:expr) => ({
        ::volatile_store(&mut $item, $value)
    });

    ($item:ident |= $value:expr) => ({
        ::volatile_store(&mut $item, ::volatile_load(&$item) | $value)
    });

    ($item:ident &= $value:expr) => ({
        ::volatile_store(&mut $item, ::volatile_load(&$item) & $value)
    });
}

pub mod ast;
pub mod nvic;
pub mod pm;
pub mod gpio;
pub mod usart;
pub mod adc;
pub mod queue;

pub struct Sam4l {
    pub ast: ast::Ast,
    pub usarts: [usart::USART; 4],
    pub adc: adc::Adc,
    pub pa00: gpio::GPIOPin, pub pa01: gpio::GPIOPin, pub pa02: gpio::GPIOPin,
    pub pa03: gpio::GPIOPin, pub pa04: gpio::GPIOPin, pub pa05: gpio::GPIOPin,
    pub pa06: gpio::GPIOPin, pub pa07: gpio::GPIOPin, pub pa08: gpio::GPIOPin,
    pub pa09: gpio::GPIOPin, pub pa10: gpio::GPIOPin, pub pa11: gpio::GPIOPin,
    pub pa12: gpio::GPIOPin, pub pa13: gpio::GPIOPin, pub pa14: gpio::GPIOPin,
    pub pa15: gpio::GPIOPin, pub pa16: gpio::GPIOPin, pub pa17: gpio::GPIOPin,
    pub pa18: gpio::GPIOPin, pub pa19: gpio::GPIOPin, pub pa20: gpio::GPIOPin,
    pub pa21: gpio::GPIOPin, pub pa22: gpio::GPIOPin, pub pa23: gpio::GPIOPin,
    pub pa24: gpio::GPIOPin, pub pa25: gpio::GPIOPin, pub pa26: gpio::GPIOPin,
    pub pa27: gpio::GPIOPin, pub pa28: gpio::GPIOPin, pub pa29: gpio::GPIOPin,
    pub pa30: gpio::GPIOPin, pub pa31: gpio::GPIOPin,

    pub pb00: gpio::GPIOPin, pub pb01: gpio::GPIOPin, pub pb02: gpio::GPIOPin,
    pub pb03: gpio::GPIOPin, pub pb04: gpio::GPIOPin, pub pb05: gpio::GPIOPin,
    pub pb06: gpio::GPIOPin, pub pb07: gpio::GPIOPin, pub pb08: gpio::GPIOPin,
    pub pb09: gpio::GPIOPin, pub pb10: gpio::GPIOPin, pub pb11: gpio::GPIOPin,
    pub pb12: gpio::GPIOPin, pub pb13: gpio::GPIOPin, pub pb14: gpio::GPIOPin,
    pub pb15: gpio::GPIOPin, pub pb16: gpio::GPIOPin, pub pb17: gpio::GPIOPin,
    pub pb18: gpio::GPIOPin, pub pb19: gpio::GPIOPin, pub pb20: gpio::GPIOPin,
    pub pb21: gpio::GPIOPin, pub pb22: gpio::GPIOPin, pub pb23: gpio::GPIOPin,
    pub pb24: gpio::GPIOPin, pub pb25: gpio::GPIOPin, pub pb26: gpio::GPIOPin,
    pub pb27: gpio::GPIOPin, pub pb28: gpio::GPIOPin, pub pb29: gpio::GPIOPin,
    pub pb30: gpio::GPIOPin, pub pb31: gpio::GPIOPin, pub pc00: gpio::GPIOPin,
    pub pc01: gpio::GPIOPin, pub pc02: gpio::GPIOPin, pub pc03: gpio::GPIOPin,
    pub pc04: gpio::GPIOPin, pub pc05: gpio::GPIOPin, pub pc06: gpio::GPIOPin,
    pub pc07: gpio::GPIOPin, pub pc08: gpio::GPIOPin, pub pc09: gpio::GPIOPin,
    pub pc10: gpio::GPIOPin, pub pc11: gpio::GPIOPin, pub pc12: gpio::GPIOPin,
    pub pc13: gpio::GPIOPin, pub pc14: gpio::GPIOPin, pub pc15: gpio::GPIOPin,
    pub pc16: gpio::GPIOPin, pub pc17: gpio::GPIOPin, pub pc18: gpio::GPIOPin,
    pub pc19: gpio::GPIOPin, pub pc20: gpio::GPIOPin, pub pc21: gpio::GPIOPin,
    pub pc22: gpio::GPIOPin, pub pc23: gpio::GPIOPin, pub pc24: gpio::GPIOPin,
    pub pc25: gpio::GPIOPin, pub pc26: gpio::GPIOPin, pub pc27: gpio::GPIOPin,
    pub pc28: gpio::GPIOPin, pub pc29: gpio::GPIOPin, pub pc30: gpio::GPIOPin,
    pub pc31: gpio::GPIOPin
}

impl Sam4l {
    pub fn new() -> Sam4l {

        Sam4l {
            ast: ast::Ast::new(),
            usarts: [
                usart::USART::new(usart::Location::USART0),
                usart::USART::new(usart::Location::USART1),
                usart::USART::new(usart::Location::USART2),
                usart::USART::new(usart::Location::USART3),
            ],
            adc: adc::Adc::new(),
            pa00: gpio::GPIOPin::new(gpio::Pin::PA00),
            pa01: gpio::GPIOPin::new(gpio::Pin::PA01),
            pa02: gpio::GPIOPin::new(gpio::Pin::PA02),
            pa03: gpio::GPIOPin::new(gpio::Pin::PA03),
            pa04: gpio::GPIOPin::new(gpio::Pin::PA04),
            pa05: gpio::GPIOPin::new(gpio::Pin::PA05),
            pa06: gpio::GPIOPin::new(gpio::Pin::PA06),
            pa07: gpio::GPIOPin::new(gpio::Pin::PA07),
            pa08: gpio::GPIOPin::new(gpio::Pin::PA08),
            pa09: gpio::GPIOPin::new(gpio::Pin::PA09),
            pa10: gpio::GPIOPin::new(gpio::Pin::PA10),
            pa11: gpio::GPIOPin::new(gpio::Pin::PA11),
            pa12: gpio::GPIOPin::new(gpio::Pin::PA12),
            pa13: gpio::GPIOPin::new(gpio::Pin::PA13),
            pa14: gpio::GPIOPin::new(gpio::Pin::PA14),
            pa15: gpio::GPIOPin::new(gpio::Pin::PA15),
            pa16: gpio::GPIOPin::new(gpio::Pin::PA16),
            pa17: gpio::GPIOPin::new(gpio::Pin::PA17),
            pa18: gpio::GPIOPin::new(gpio::Pin::PA18),
            pa19: gpio::GPIOPin::new(gpio::Pin::PA19),
            pa20: gpio::GPIOPin::new(gpio::Pin::PA20),
            pa21: gpio::GPIOPin::new(gpio::Pin::PA21),
            pa22: gpio::GPIOPin::new(gpio::Pin::PA22),
            pa23: gpio::GPIOPin::new(gpio::Pin::PA23),
            pa24: gpio::GPIOPin::new(gpio::Pin::PA24),
            pa25: gpio::GPIOPin::new(gpio::Pin::PA25),
            pa26: gpio::GPIOPin::new(gpio::Pin::PA26),
            pa27: gpio::GPIOPin::new(gpio::Pin::PA27),
            pa28: gpio::GPIOPin::new(gpio::Pin::PA28),
            pa29: gpio::GPIOPin::new(gpio::Pin::PA29),
            pa30: gpio::GPIOPin::new(gpio::Pin::PA30),
            pa31: gpio::GPIOPin::new(gpio::Pin::PA31),

            pb00: gpio::GPIOPin::new(gpio::Pin::PB00),
            pb01: gpio::GPIOPin::new(gpio::Pin::PB01),
            pb02: gpio::GPIOPin::new(gpio::Pin::PB02),
            pb03: gpio::GPIOPin::new(gpio::Pin::PB03),
            pb04: gpio::GPIOPin::new(gpio::Pin::PB04),
            pb05: gpio::GPIOPin::new(gpio::Pin::PB05),
            pb06: gpio::GPIOPin::new(gpio::Pin::PB06),
            pb07: gpio::GPIOPin::new(gpio::Pin::PB07),
            pb08: gpio::GPIOPin::new(gpio::Pin::PB08),
            pb09: gpio::GPIOPin::new(gpio::Pin::PB09),
            pb10: gpio::GPIOPin::new(gpio::Pin::PB10),
            pb11: gpio::GPIOPin::new(gpio::Pin::PB11),
            pb12: gpio::GPIOPin::new(gpio::Pin::PB12),
            pb13: gpio::GPIOPin::new(gpio::Pin::PB13),
            pb14: gpio::GPIOPin::new(gpio::Pin::PB14),
            pb15: gpio::GPIOPin::new(gpio::Pin::PB15),
            pb16: gpio::GPIOPin::new(gpio::Pin::PB16),
            pb17: gpio::GPIOPin::new(gpio::Pin::PB17),
            pb18: gpio::GPIOPin::new(gpio::Pin::PB18),
            pb19: gpio::GPIOPin::new(gpio::Pin::PB19),
            pb20: gpio::GPIOPin::new(gpio::Pin::PB20),
            pb21: gpio::GPIOPin::new(gpio::Pin::PB21),
            pb22: gpio::GPIOPin::new(gpio::Pin::PB22),
            pb23: gpio::GPIOPin::new(gpio::Pin::PB23),
            pb24: gpio::GPIOPin::new(gpio::Pin::PB24),
            pb25: gpio::GPIOPin::new(gpio::Pin::PB25),
            pb26: gpio::GPIOPin::new(gpio::Pin::PB26),
            pb27: gpio::GPIOPin::new(gpio::Pin::PB27),
            pb28: gpio::GPIOPin::new(gpio::Pin::PB28),
            pb29: gpio::GPIOPin::new(gpio::Pin::PB29),
            pb30: gpio::GPIOPin::new(gpio::Pin::PB30),
            pb31: gpio::GPIOPin::new(gpio::Pin::PB31),

            pc00: gpio::GPIOPin::new(gpio::Pin::PC00),
            pc01: gpio::GPIOPin::new(gpio::Pin::PC01),
            pc02: gpio::GPIOPin::new(gpio::Pin::PC02),
            pc03: gpio::GPIOPin::new(gpio::Pin::PC03),
            pc04: gpio::GPIOPin::new(gpio::Pin::PC04),
            pc05: gpio::GPIOPin::new(gpio::Pin::PC05),
            pc06: gpio::GPIOPin::new(gpio::Pin::PC06),
            pc07: gpio::GPIOPin::new(gpio::Pin::PC07),
            pc08: gpio::GPIOPin::new(gpio::Pin::PC08),
            pc09: gpio::GPIOPin::new(gpio::Pin::PC09),
            pc10: gpio::GPIOPin::new(gpio::Pin::PC10),
            pc11: gpio::GPIOPin::new(gpio::Pin::PC11),
            pc12: gpio::GPIOPin::new(gpio::Pin::PC12),
            pc13: gpio::GPIOPin::new(gpio::Pin::PC13),
            pc14: gpio::GPIOPin::new(gpio::Pin::PC14),
            pc15: gpio::GPIOPin::new(gpio::Pin::PC15),
            pc16: gpio::GPIOPin::new(gpio::Pin::PC16),
            pc17: gpio::GPIOPin::new(gpio::Pin::PC17),
            pc18: gpio::GPIOPin::new(gpio::Pin::PC18),
            pc19: gpio::GPIOPin::new(gpio::Pin::PC19),
            pc20: gpio::GPIOPin::new(gpio::Pin::PC20),
            pc21: gpio::GPIOPin::new(gpio::Pin::PC21),
            pc22: gpio::GPIOPin::new(gpio::Pin::PC22),
            pc23: gpio::GPIOPin::new(gpio::Pin::PC23),
            pc24: gpio::GPIOPin::new(gpio::Pin::PC24),
            pc25: gpio::GPIOPin::new(gpio::Pin::PC25),
            pc26: gpio::GPIOPin::new(gpio::Pin::PC26),
            pc27: gpio::GPIOPin::new(gpio::Pin::PC27),
            pc28: gpio::GPIOPin::new(gpio::Pin::PC28),
            pc29: gpio::GPIOPin::new(gpio::Pin::PC29),
            pc30: gpio::GPIOPin::new(gpio::Pin::PC30),
            pc31: gpio::GPIOPin::new(gpio::Pin::PC31),
        }
    }

    pub unsafe fn service_pending_interrupts(&mut self) {
        use core::intrinsics::atomic_xchg;
        // This should be implemented as a lock-free queue
        // of handler identifiers -pal
        if atomic_xchg(&mut ast::INTERRUPT, false) {
            self.ast.handle_interrupt();
            nvic::enable(nvic::NvicIdx::ASTALARM);
        }

        if atomic_xchg(&mut usart::USART3_INTERRUPT, false) {
            self.usarts[3].handle_interrupt();
            nvic::enable(nvic::NvicIdx::USART3);
        }

        if atomic_xchg(&mut adc::ADC_INTERRUPT, false) {
            self.adc.handle_interrupt();
            nvic::enable(nvic::NvicIdx::ADCIFE);
        }

    }

    pub fn has_pending_interrupts(&mut self) -> bool {
        use core::intrinsics::volatile_load;
        unsafe {
            volatile_load(&usart::USART3_INTERRUPT)
                || volatile_load(&ast::INTERRUPT)
        }
    }
}

<commit_msg>Added interrupt queue. Doesn't compile due to missing arm-gcc symbol.<commit_after>#![crate_name = "sam4l"]
#![crate_type = "rlib"]
#![feature(asm,core,concat_idents,no_std)]
#![no_std]

extern crate core;
extern crate common;
extern crate hil;

pub fn volatile_load<T>(item: &T) -> T {
    unsafe {
        core::intrinsics::volatile_load(item)
    }
}

pub fn volatile_store<T>(item: &mut T, val: T) {
    unsafe {
        core::intrinsics::volatile_store(item, val)
    }
}

macro_rules! volatile {
    ($item:expr) => ({
        ::volatile_load(&$item)
    });

    ($item:ident = $value:expr) => ({
        ::volatile_store(&mut $item, $value)
    });

    ($item:ident |= $value:expr) => ({
        ::volatile_store(&mut $item, ::volatile_load(&$item) | $value)
    });

    ($item:ident &= $value:expr) => ({
        ::volatile_store(&mut $item, ::volatile_load(&$item) & $value)
    });
}

pub mod ast;
pub mod nvic;
pub mod pm;
pub mod gpio;
pub mod usart;
pub mod adc;
pub mod queue;

pub struct Sam4l {
    pub queue: queue::InterruptQueue,
    pub ast: ast::Ast,
    pub usarts: [usart::USART; 4],
    pub adc: adc::Adc,
    pub pa00: gpio::GPIOPin, pub pa01: gpio::GPIOPin, pub pa02: gpio::GPIOPin,
    pub pa03: gpio::GPIOPin, pub pa04: gpio::GPIOPin, pub pa05: gpio::GPIOPin,
    pub pa06: gpio::GPIOPin, pub pa07: gpio::GPIOPin, pub pa08: gpio::GPIOPin,
    pub pa09: gpio::GPIOPin, pub pa10: gpio::GPIOPin, pub pa11: gpio::GPIOPin,
    pub pa12: gpio::GPIOPin, pub pa13: gpio::GPIOPin, pub pa14: gpio::GPIOPin,
    pub pa15: gpio::GPIOPin, pub pa16: gpio::GPIOPin, pub pa17: gpio::GPIOPin,
    pub pa18: gpio::GPIOPin, pub pa19: gpio::GPIOPin, pub pa20: gpio::GPIOPin,
    pub pa21: gpio::GPIOPin, pub pa22: gpio::GPIOPin, pub pa23: gpio::GPIOPin,
    pub pa24: gpio::GPIOPin, pub pa25: gpio::GPIOPin, pub pa26: gpio::GPIOPin,
    pub pa27: gpio::GPIOPin, pub pa28: gpio::GPIOPin, pub pa29: gpio::GPIOPin,
    pub pa30: gpio::GPIOPin, pub pa31: gpio::GPIOPin,

    pub pb00: gpio::GPIOPin, pub pb01: gpio::GPIOPin, pub pb02: gpio::GPIOPin,
    pub pb03: gpio::GPIOPin, pub pb04: gpio::GPIOPin, pub pb05: gpio::GPIOPin,
    pub pb06: gpio::GPIOPin, pub pb07: gpio::GPIOPin, pub pb08: gpio::GPIOPin,
    pub pb09: gpio::GPIOPin, pub pb10: gpio::GPIOPin, pub pb11: gpio::GPIOPin,
    pub pb12: gpio::GPIOPin, pub pb13: gpio::GPIOPin, pub pb14: gpio::GPIOPin,
    pub pb15: gpio::GPIOPin, pub pb16: gpio::GPIOPin, pub pb17: gpio::GPIOPin,
    pub pb18: gpio::GPIOPin, pub pb19: gpio::GPIOPin, pub pb20: gpio::GPIOPin,
    pub pb21: gpio::GPIOPin, pub pb22: gpio::GPIOPin, pub pb23: gpio::GPIOPin,
    pub pb24: gpio::GPIOPin, pub pb25: gpio::GPIOPin, pub pb26: gpio::GPIOPin,
    pub pb27: gpio::GPIOPin, pub pb28: gpio::GPIOPin, pub pb29: gpio::GPIOPin,
    pub pb30: gpio::GPIOPin, pub pb31: gpio::GPIOPin, pub pc00: gpio::GPIOPin,
    pub pc01: gpio::GPIOPin, pub pc02: gpio::GPIOPin, pub pc03: gpio::GPIOPin,
    pub pc04: gpio::GPIOPin, pub pc05: gpio::GPIOPin, pub pc06: gpio::GPIOPin,
    pub pc07: gpio::GPIOPin, pub pc08: gpio::GPIOPin, pub pc09: gpio::GPIOPin,
    pub pc10: gpio::GPIOPin, pub pc11: gpio::GPIOPin, pub pc12: gpio::GPIOPin,
    pub pc13: gpio::GPIOPin, pub pc14: gpio::GPIOPin, pub pc15: gpio::GPIOPin,
    pub pc16: gpio::GPIOPin, pub pc17: gpio::GPIOPin, pub pc18: gpio::GPIOPin,
    pub pc19: gpio::GPIOPin, pub pc20: gpio::GPIOPin, pub pc21: gpio::GPIOPin,
    pub pc22: gpio::GPIOPin, pub pc23: gpio::GPIOPin, pub pc24: gpio::GPIOPin,
    pub pc25: gpio::GPIOPin, pub pc26: gpio::GPIOPin, pub pc27: gpio::GPIOPin,
    pub pc28: gpio::GPIOPin, pub pc29: gpio::GPIOPin, pub pc30: gpio::GPIOPin,
    pub pc31: gpio::GPIOPin
}

impl Sam4l {
    pub fn new() -> Sam4l {

        Sam4l {
            queue: queue::InterruptQueue::new(),
            ast: ast::Ast::new(),
            usarts: [
                usart::USART::new(usart::Location::USART0),
                usart::USART::new(usart::Location::USART1),
                usart::USART::new(usart::Location::USART2),
                usart::USART::new(usart::Location::USART3),
            ],
            adc: adc::Adc::new(),
            pa00: gpio::GPIOPin::new(gpio::Pin::PA00),
            pa01: gpio::GPIOPin::new(gpio::Pin::PA01),
            pa02: gpio::GPIOPin::new(gpio::Pin::PA02),
            pa03: gpio::GPIOPin::new(gpio::Pin::PA03),
            pa04: gpio::GPIOPin::new(gpio::Pin::PA04),
            pa05: gpio::GPIOPin::new(gpio::Pin::PA05),
            pa06: gpio::GPIOPin::new(gpio::Pin::PA06),
            pa07: gpio::GPIOPin::new(gpio::Pin::PA07),
            pa08: gpio::GPIOPin::new(gpio::Pin::PA08),
            pa09: gpio::GPIOPin::new(gpio::Pin::PA09),
            pa10: gpio::GPIOPin::new(gpio::Pin::PA10),
            pa11: gpio::GPIOPin::new(gpio::Pin::PA11),
            pa12: gpio::GPIOPin::new(gpio::Pin::PA12),
            pa13: gpio::GPIOPin::new(gpio::Pin::PA13),
            pa14: gpio::GPIOPin::new(gpio::Pin::PA14),
            pa15: gpio::GPIOPin::new(gpio::Pin::PA15),
            pa16: gpio::GPIOPin::new(gpio::Pin::PA16),
            pa17: gpio::GPIOPin::new(gpio::Pin::PA17),
            pa18: gpio::GPIOPin::new(gpio::Pin::PA18),
            pa19: gpio::GPIOPin::new(gpio::Pin::PA19),
            pa20: gpio::GPIOPin::new(gpio::Pin::PA20),
            pa21: gpio::GPIOPin::new(gpio::Pin::PA21),
            pa22: gpio::GPIOPin::new(gpio::Pin::PA22),
            pa23: gpio::GPIOPin::new(gpio::Pin::PA23),
            pa24: gpio::GPIOPin::new(gpio::Pin::PA24),
            pa25: gpio::GPIOPin::new(gpio::Pin::PA25),
            pa26: gpio::GPIOPin::new(gpio::Pin::PA26),
            pa27: gpio::GPIOPin::new(gpio::Pin::PA27),
            pa28: gpio::GPIOPin::new(gpio::Pin::PA28),
            pa29: gpio::GPIOPin::new(gpio::Pin::PA29),
            pa30: gpio::GPIOPin::new(gpio::Pin::PA30),
            pa31: gpio::GPIOPin::new(gpio::Pin::PA31),

            pb00: gpio::GPIOPin::new(gpio::Pin::PB00),
            pb01: gpio::GPIOPin::new(gpio::Pin::PB01),
            pb02: gpio::GPIOPin::new(gpio::Pin::PB02),
            pb03: gpio::GPIOPin::new(gpio::Pin::PB03),
            pb04: gpio::GPIOPin::new(gpio::Pin::PB04),
            pb05: gpio::GPIOPin::new(gpio::Pin::PB05),
            pb06: gpio::GPIOPin::new(gpio::Pin::PB06),
            pb07: gpio::GPIOPin::new(gpio::Pin::PB07),
            pb08: gpio::GPIOPin::new(gpio::Pin::PB08),
            pb09: gpio::GPIOPin::new(gpio::Pin::PB09),
            pb10: gpio::GPIOPin::new(gpio::Pin::PB10),
            pb11: gpio::GPIOPin::new(gpio::Pin::PB11),
            pb12: gpio::GPIOPin::new(gpio::Pin::PB12),
            pb13: gpio::GPIOPin::new(gpio::Pin::PB13),
            pb14: gpio::GPIOPin::new(gpio::Pin::PB14),
            pb15: gpio::GPIOPin::new(gpio::Pin::PB15),
            pb16: gpio::GPIOPin::new(gpio::Pin::PB16),
            pb17: gpio::GPIOPin::new(gpio::Pin::PB17),
            pb18: gpio::GPIOPin::new(gpio::Pin::PB18),
            pb19: gpio::GPIOPin::new(gpio::Pin::PB19),
            pb20: gpio::GPIOPin::new(gpio::Pin::PB20),
            pb21: gpio::GPIOPin::new(gpio::Pin::PB21),
            pb22: gpio::GPIOPin::new(gpio::Pin::PB22),
            pb23: gpio::GPIOPin::new(gpio::Pin::PB23),
            pb24: gpio::GPIOPin::new(gpio::Pin::PB24),
            pb25: gpio::GPIOPin::new(gpio::Pin::PB25),
            pb26: gpio::GPIOPin::new(gpio::Pin::PB26),
            pb27: gpio::GPIOPin::new(gpio::Pin::PB27),
            pb28: gpio::GPIOPin::new(gpio::Pin::PB28),
            pb29: gpio::GPIOPin::new(gpio::Pin::PB29),
            pb30: gpio::GPIOPin::new(gpio::Pin::PB30),
            pb31: gpio::GPIOPin::new(gpio::Pin::PB31),

            pc00: gpio::GPIOPin::new(gpio::Pin::PC00),
            pc01: gpio::GPIOPin::new(gpio::Pin::PC01),
            pc02: gpio::GPIOPin::new(gpio::Pin::PC02),
            pc03: gpio::GPIOPin::new(gpio::Pin::PC03),
            pc04: gpio::GPIOPin::new(gpio::Pin::PC04),
            pc05: gpio::GPIOPin::new(gpio::Pin::PC05),
            pc06: gpio::GPIOPin::new(gpio::Pin::PC06),
            pc07: gpio::GPIOPin::new(gpio::Pin::PC07),
            pc08: gpio::GPIOPin::new(gpio::Pin::PC08),
            pc09: gpio::GPIOPin::new(gpio::Pin::PC09),
            pc10: gpio::GPIOPin::new(gpio::Pin::PC10),
            pc11: gpio::GPIOPin::new(gpio::Pin::PC11),
            pc12: gpio::GPIOPin::new(gpio::Pin::PC12),
            pc13: gpio::GPIOPin::new(gpio::Pin::PC13),
            pc14: gpio::GPIOPin::new(gpio::Pin::PC14),
            pc15: gpio::GPIOPin::new(gpio::Pin::PC15),
            pc16: gpio::GPIOPin::new(gpio::Pin::PC16),
            pc17: gpio::GPIOPin::new(gpio::Pin::PC17),
            pc18: gpio::GPIOPin::new(gpio::Pin::PC18),
            pc19: gpio::GPIOPin::new(gpio::Pin::PC19),
            pc20: gpio::GPIOPin::new(gpio::Pin::PC20),
            pc21: gpio::GPIOPin::new(gpio::Pin::PC21),
            pc22: gpio::GPIOPin::new(gpio::Pin::PC22),
            pc23: gpio::GPIOPin::new(gpio::Pin::PC23),
            pc24: gpio::GPIOPin::new(gpio::Pin::PC24),
            pc25: gpio::GPIOPin::new(gpio::Pin::PC25),
            pc26: gpio::GPIOPin::new(gpio::Pin::PC26),
            pc27: gpio::GPIOPin::new(gpio::Pin::PC27),
            pc28: gpio::GPIOPin::new(gpio::Pin::PC28),
            pc29: gpio::GPIOPin::new(gpio::Pin::PC29),
            pc30: gpio::GPIOPin::new(gpio::Pin::PC30),
            pc31: gpio::GPIOPin::new(gpio::Pin::PC31),
        }
    }

    pub unsafe fn service_pending_interrupts(&mut self) {
        use core::intrinsics::atomic_xchg;
        // This should be implemented as a lock-free queue
        // of handler identifiers -pal
        if atomic_xchg(&mut ast::INTERRUPT, false) {
            self.ast.handle_interrupt();
            nvic::enable(nvic::NvicIdx::ASTALARM);
        }

        if atomic_xchg(&mut usart::USART3_INTERRUPT, false) {
            self.usarts[3].handle_interrupt();
            nvic::enable(nvic::NvicIdx::USART3);
        }

        if atomic_xchg(&mut adc::ADC_INTERRUPT, false) {
            self.adc.handle_interrupt();
            nvic::enable(nvic::NvicIdx::ADCIFE);
        }

    }

    pub fn has_pending_interrupts(&mut self) -> bool {
        use core::intrinsics::volatile_load;
        unsafe {
            volatile_load(&usart::USART3_INTERRUPT)
                || volatile_load(&ast::INTERRUPT)
        }
    }
}

<|endoftext|>


<commit_before>use ra_syntax::{
    ast::{self, NameOwner, VisibilityOwner},
    AstNode,
    SyntaxKind::{
        ATTR, COMMENT, CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY,
        WHITESPACE,
    },
    SyntaxNode, TextSize, T,
};
use test_utils::tested_by;

use crate::{AssistContext, AssistId, Assists};

// Assist: change_visibility
//
// Adds or changes existing visibility specifier.
//
// ```
// <|>fn frobnicate() {}
// ```
// ->
// ```
// pub(crate) fn frobnicate() {}
// ```
pub(crate) fn change_visibility(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    if let Some(vis) = ctx.find_node_at_offset::<ast::Visibility>() {
        return change_vis(acc, vis);
    }
    add_vis(acc, ctx)
}

fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() {
        T![const] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait] => true,
        _ => false,
    });

    let (offset, target) = if let Some(keyword) = item_keyword {
        let parent = keyword.parent();
        let def_kws = vec![CONST_DEF, FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF];
        // Parent is not a definition, can't add visibility
        if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) {
            return None;
        }
        // Already have visibility, do nothing
        if parent.children().any(|child| child.kind() == VISIBILITY) {
            return None;
        }
        (vis_offset(&parent), keyword.text_range())
    } else if let Some(field_name) = ctx.find_node_at_offset::<ast::Name>() {
        let field = field_name.syntax().ancestors().find_map(ast::RecordFieldDef::cast)?;
        if field.name()? != field_name {
            tested_by!(change_visibility_field_false_positive);
            return None;
        }
        if field.visibility().is_some() {
            return None;
        }
        (vis_offset(field.syntax()), field_name.syntax().text_range())
    } else if let Some(field) = ctx.find_node_at_offset::<ast::TupleFieldDef>() {
        if field.visibility().is_some() {
            return None;
        }
        (vis_offset(field.syntax()), field.syntax().text_range())
    } else {
        return None;
    };

    acc.add(AssistId("change_visibility"), "Change visibility to pub(crate)", target, |edit| {
        edit.insert(offset, "pub(crate) ");
        edit.set_cursor(offset);
    })
}

fn vis_offset(node: &SyntaxNode) -> TextSize {
    node.children_with_tokens()
        .skip_while(|it| match it.kind() {
            WHITESPACE | COMMENT | ATTR => true,
            _ => false,
        })
        .next()
        .map(|it| it.text_range().start())
        .unwrap_or_else(|| node.text_range().start())
}

fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> {
    if vis.syntax().text() == "pub" {
        let target = vis.syntax().text_range();
        return acc.add(
            AssistId("change_visibility"),
            "Change Visibility to pub(crate)",
            target,
            |edit| {
                edit.replace(vis.syntax().text_range(), "pub(crate)");
                edit.set_cursor(vis.syntax().text_range().start())
            },
        );
    }
    if vis.syntax().text() == "pub(crate)" {
        let target = vis.syntax().text_range();
        return acc.add(
            AssistId("change_visibility"),
            "Change visibility to pub",
            target,
            |edit| {
                edit.replace(vis.syntax().text_range(), "pub");
                edit.set_cursor(vis.syntax().text_range().start());
            },
        );
    }
    None
}

#[cfg(test)]
mod tests {
    use test_utils::covers;

    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};

    use super::*;

    #[test]
    fn change_visibility_adds_pub_crate_to_items() {
        check_assist(change_visibility, "<|>fn foo() {}", "<|>pub(crate) fn foo() {}");
        check_assist(change_visibility, "f<|>n foo() {}", "<|>pub(crate) fn foo() {}");
        check_assist(change_visibility, "<|>struct Foo {}", "<|>pub(crate) struct Foo {}");
        check_assist(change_visibility, "<|>mod foo {}", "<|>pub(crate) mod foo {}");
        check_assist(change_visibility, "<|>trait Foo {}", "<|>pub(crate) trait Foo {}");
        check_assist(change_visibility, "m<|>od {}", "<|>pub(crate) mod {}");
        check_assist(
            change_visibility,
            "unsafe f<|>n foo() {}",
            "<|>pub(crate) unsafe fn foo() {}",
        );
    }

    #[test]
    fn change_visibility_works_with_struct_fields() {
        check_assist(
            change_visibility,
            r"struct S { <|>field: u32 }",
            r"struct S { <|>pub(crate) field: u32 }",
        );
        check_assist(change_visibility, r"struct S ( <|>u32 )", r"struct S ( <|>pub(crate) u32 )");
    }

    #[test]
    fn change_visibility_field_false_positive() {
        covers!(change_visibility_field_false_positive);
        check_assist_not_applicable(
            change_visibility,
            r"struct S { field: [(); { let <|>x = ();}] }",
        )
    }

    #[test]
    fn change_visibility_pub_to_pub_crate() {
        check_assist(change_visibility, "<|>pub fn foo() {}", "<|>pub(crate) fn foo() {}")
    }

    #[test]
    fn change_visibility_pub_crate_to_pub() {
        check_assist(change_visibility, "<|>pub(crate) fn foo() {}", "<|>pub fn foo() {}")
    }

    #[test]
    fn change_visibility_const() {
        check_assist(change_visibility, "<|>const FOO = 3u8;", "<|>pub(crate) const FOO = 3u8;");
    }

    #[test]
    fn change_visibility_handles_comment_attrs() {
        check_assist(
            change_visibility,
            r"
            /// docs

            // comments

            #[derive(Debug)]
            <|>struct Foo;
            ",
            r"
            /// docs

            // comments

            #[derive(Debug)]
            <|>pub(crate) struct Foo;
            ",
        )
    }

    #[test]
    fn change_visibility_target() {
        check_assist_target(change_visibility, "<|>fn foo() {}", "fn");
        check_assist_target(change_visibility, "pub(crate)<|> fn foo() {}", "pub(crate)");
        check_assist_target(change_visibility, "struct S { <|>field: u32 }", "field");
    }
}
<commit_msg>Trigger change_visibility assist when on a path to an invisible def<commit_after>use ra_syntax::{
    ast::{self, NameOwner, VisibilityOwner},
    AstNode,
    SyntaxKind::{
        ATTR, COMMENT, CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY,
        WHITESPACE,
    },
    SyntaxNode, TextRange, TextSize, T,
};

use hir::{db::HirDatabase, HasSource, PathResolution};
use test_utils::tested_by;

use crate::{AssistContext, AssistId, Assists};

// Assist: change_visibility
//
// Adds or changes existing visibility specifier.
//
// ```
// <|>fn frobnicate() {}
// ```
// ->
// ```
// pub(crate) fn frobnicate() {}
// ```
pub(crate) fn change_visibility(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    if let Some(vis) = ctx.find_node_at_offset::<ast::Visibility>() {
        return change_vis(acc, vis);
    }
    add_vis(acc, ctx)
}

fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() {
        T![const] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait] => true,
        _ => false,
    });

    let (offset, target) = if let Some(keyword) = item_keyword {
        let parent = keyword.parent();
        let def_kws = vec![CONST_DEF, FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF];
        // Parent is not a definition, can't add visibility
        if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) {
            return None;
        }
        // Already have visibility, do nothing
        if parent.children().any(|child| child.kind() == VISIBILITY) {
            return None;
        }
        (vis_offset(&parent), keyword.text_range())
    } else if let Some(field_name) = ctx.find_node_at_offset::<ast::Name>() {
        let field = field_name.syntax().ancestors().find_map(ast::RecordFieldDef::cast)?;
        if field.name()? != field_name {
            tested_by!(change_visibility_field_false_positive);
            return None;
        }
        if field.visibility().is_some() {
            return None;
        }
        (vis_offset(field.syntax()), field_name.syntax().text_range())
    } else if let Some(field) = ctx.find_node_at_offset::<ast::TupleFieldDef>() {
        if field.visibility().is_some() {
            return None;
        }
        (vis_offset(field.syntax()), field.syntax().text_range())
    } else {
        return None;
    };

    acc.add(AssistId("change_visibility"), "Change visibility to pub(crate)", target, |edit| {
        edit.insert(offset, "pub(crate) ");
        edit.set_cursor(offset);
    })
}

fn add_missing_vis(ctx: AssistCtx) -> Option<Assist> {
    let path: ast::Path = ctx.find_node_at_offset()?;
    let path_res = dbg!(ctx.sema.resolve_path(&path))?;
    let def = match path_res {
        PathResolution::Def(def) => def,
        _ => return None,
    };
    dbg!(&def);

    let current_module = dbg!(ctx.sema.scope(&path.syntax()).module())?;
    let target_module = dbg!(def.module(ctx.db))?;

    let vis = dbg!(target_module.visibility_of(ctx.db, &def))?;
    if vis.is_visible_from(ctx.db, current_module.into()) {
        return None;
    };
    let target_name;

    let (offset, target) = match def {
        hir::ModuleDef::Function(f) => {
            target_name = Some(f.name(ctx.db));
            offset_and_target(ctx.db, f)
        }
        hir::ModuleDef::Adt(adt) => {
            target_name = Some(adt.name(ctx.db));
            match adt {
                hir::Adt::Struct(s) => offset_and_target(ctx.db, s),
                hir::Adt::Union(u) => offset_and_target(ctx.db, u),
                hir::Adt::Enum(e) => offset_and_target(ctx.db, e),
            }
        }
        hir::ModuleDef::Const(c) => {
            target_name = c.name(ctx.db);
            offset_and_target(ctx.db, c)
        }
        hir::ModuleDef::Static(s) => {
            target_name = s.name(ctx.db);
            offset_and_target(ctx.db, s)
        }
        hir::ModuleDef::Trait(t) => {
            target_name = Some(t.name(ctx.db));
            offset_and_target(ctx.db, t)
        }
        hir::ModuleDef::TypeAlias(t) => {
            target_name = Some(t.name(ctx.db));
            offset_and_target(ctx.db, t)
        }
        hir::ModuleDef::Module(m) => {
            target_name = m.name(ctx.db);
            let source = dbg!(m.declaration_source(ctx.db))?.value;
            let syntax = source.syntax();
            (vis_offset(syntax), syntax.text_range())
        }
        // Enum variants can't be private, we can't modify builtin types
        hir::ModuleDef::EnumVariant(_) | hir::ModuleDef::BuiltinType(_) => return None,
    };

    // FIXME if target is in another crate, add `pub` instead of `pub(crate)`

    let assist_label = match target_name {
        None => "Change visibility to pub(crate)".to_string(),
        Some(name) => format!("Change visibility of {} to pub(crate)", name),
    };
    let target_file = target_module.definition_source(ctx.db).file_id.original_file(ctx.db);

    ctx.add_assist(AssistId("change_visibility"), assist_label, target, |edit| {
        edit.set_file(target_file);
        edit.insert(offset, "pub(crate) ");
        edit.set_cursor(offset);
    })
}

fn offset_and_target<S, Ast>(db: &dyn HirDatabase, x: S) -> (TextSize, TextRange)
where
    S: HasSource<Ast = Ast>,
    Ast: AstNode,
{
    let source = x.source(db);
    let syntax = source.syntax().value;
    (vis_offset(syntax), syntax.text_range())
}

fn vis_offset(node: &SyntaxNode) -> TextSize {
    node.children_with_tokens()
        .skip_while(|it| match it.kind() {
            WHITESPACE | COMMENT | ATTR => true,
            _ => false,
        })
        .next()
        .map(|it| it.text_range().start())
        .unwrap_or_else(|| node.text_range().start())
}

fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> {
    if vis.syntax().text() == "pub" {
        let target = vis.syntax().text_range();
        return acc.add(
            AssistId("change_visibility"),
            "Change Visibility to pub(crate)",
            target,
            |edit| {
                edit.replace(vis.syntax().text_range(), "pub(crate)");
                edit.set_cursor(vis.syntax().text_range().start())
            },
        );
    }
    if vis.syntax().text() == "pub(crate)" {
        let target = vis.syntax().text_range();
        return acc.add(
            AssistId("change_visibility"),
            "Change visibility to pub",
            target,
            |edit| {
                edit.replace(vis.syntax().text_range(), "pub");
                edit.set_cursor(vis.syntax().text_range().start());
            },
        );
    }
    None
}

#[cfg(test)]
mod tests {
    use test_utils::covers;

    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};

    use super::*;

    #[test]
    fn change_visibility_adds_pub_crate_to_items() {
        check_assist(change_visibility, "<|>fn foo() {}", "<|>pub(crate) fn foo() {}");
        check_assist(change_visibility, "f<|>n foo() {}", "<|>pub(crate) fn foo() {}");
        check_assist(change_visibility, "<|>struct Foo {}", "<|>pub(crate) struct Foo {}");
        check_assist(change_visibility, "<|>mod foo {}", "<|>pub(crate) mod foo {}");
        check_assist(change_visibility, "<|>trait Foo {}", "<|>pub(crate) trait Foo {}");
        check_assist(change_visibility, "m<|>od {}", "<|>pub(crate) mod {}");
        check_assist(
            change_visibility,
            "unsafe f<|>n foo() {}",
            "<|>pub(crate) unsafe fn foo() {}",
        );
    }

    #[test]
    fn change_visibility_works_with_struct_fields() {
        check_assist(
            change_visibility,
            r"struct S { <|>field: u32 }",
            r"struct S { <|>pub(crate) field: u32 }",
        );
        check_assist(change_visibility, r"struct S ( <|>u32 )", r"struct S ( <|>pub(crate) u32 )");
    }

    #[test]
    fn change_visibility_field_false_positive() {
        covers!(change_visibility_field_false_positive);
        check_assist_not_applicable(
            change_visibility,
            r"struct S { field: [(); { let <|>x = ();}] }",
        )
    }

    #[test]
    fn change_visibility_pub_to_pub_crate() {
        check_assist(change_visibility, "<|>pub fn foo() {}", "<|>pub(crate) fn foo() {}")
    }

    #[test]
    fn change_visibility_pub_crate_to_pub() {
        check_assist(change_visibility, "<|>pub(crate) fn foo() {}", "<|>pub fn foo() {}")
    }

    #[test]
    fn change_visibility_const() {
        check_assist(change_visibility, "<|>const FOO = 3u8;", "<|>pub(crate) const FOO = 3u8;");
    }

    #[test]
    fn change_visibility_handles_comment_attrs() {
        check_assist(
            change_visibility,
            r"
            /// docs

            // comments

            #[derive(Debug)]
            <|>struct Foo;
            ",
            r"
            /// docs

            // comments

            #[derive(Debug)]
            <|>pub(crate) struct Foo;
            ",
        )
    }

    #[test]
    fn change_visibility_of_fn_via_path() {
        check_assist(
            change_visibility,
            r"mod foo { fn foo() {} }
              fn main() { foo::foo<|>() } ",
            r"mod foo { <|>pub(crate) fn foo() {} }
              fn main() { foo::foo() } ",
        );
        check_assist_not_applicable(
            change_visibility,
            r"mod foo { pub fn foo() {} }
              fn main() { foo::foo<|>() } ",
        )
    }

    #[test]
    fn change_visibility_of_adt_in_submodule_via_path() {
        check_assist(
            change_visibility,
            r"mod foo { struct Foo; }
              fn main() { foo::Foo<|> } ",
            r"mod foo { <|>pub(crate) struct Foo; }
              fn main() { foo::Foo } ",
        );
        check_assist_not_applicable(
            change_visibility,
            r"mod foo { pub struct Foo; }
              fn main() { foo::Foo<|> } ",
        );
        check_assist(
            change_visibility,
            r"mod foo { enum Foo; }
              fn main() { foo::Foo<|> } ",
            r"mod foo { <|>pub(crate) enum Foo; }
              fn main() { foo::Foo } ",
        );
        check_assist_not_applicable(
            change_visibility,
            r"mod foo { pub enum Foo; }
              fn main() { foo::Foo<|> } ",
        );
        check_assist(
            change_visibility,
            r"mod foo { union Foo; }
              fn main() { foo::Foo<|> } ",
            r"mod foo { <|>pub(crate) union Foo; }
              fn main() { foo::Foo } ",
        );
        check_assist_not_applicable(
            change_visibility,
            r"mod foo { pub union Foo; }
              fn main() { foo::Foo<|> } ",
        );
    }

    #[test]
    fn change_visibility_of_adt_in_other_file_via_path() {
        check_assist(
            change_visibility,
            r"
              //- /main.rs
              mod foo;
              fn main() { foo::Foo<|> }

              //- /foo.rs
              struct Foo;
              ",
            r"<|>pub(crate) struct Foo;

",
        );
    }

    #[test]
    // FIXME this requires a separate implementation, struct fields are not a ast::Path
    fn change_visibility_of_struct_field_via_path() {
        check_assist(
            change_visibility,
            r"mod foo { pub struct Foo { bar: (), } }
              fn main() { foo::Foo { <|>bar: () }; } ",
            r"mod foo { pub struct Foo { <|>pub(crate) bar: (), } }
              fn main() { foo::Foo { bar: () }; } ",
        );
        check_assist_not_applicable(
            change_visibility,
            r"mod foo { pub struct Foo { pub bar: (), } }
              fn main() { foo::Foo { <|>bar: () }; } ",
        );
    }

    #[test]
    fn not_applicable_for_enum_variants() {
        check_assist_not_applicable(
            change_visibility,
            r"mod foo { pub enum Foo {Foo1} }
              fn main() { foo::Foo::Foo1<|> } ",
        );
    }

    #[test]
    fn change_visibility_of_const_via_path() {
        check_assist(
            change_visibility,
            r"mod foo { const FOO: () = (); }
              fn main() { foo::FOO<|> } ",
            r"mod foo { <|>pub(crate) const FOO: () = (); }
              fn main() { foo::FOO } ",
        );
        check_assist_not_applicable(
            change_visibility,
            r"mod foo { pub const FOO: () = (); }
              fn main() { foo::FOO<|> } ",
        );
    }

    #[test]
    fn change_visibility_of_static_via_path() {
        check_assist(
            change_visibility,
            r"mod foo { static FOO: () = (); }
              fn main() { foo::FOO<|> } ",
            r"mod foo { <|>pub(crate) static FOO: () = (); }
              fn main() { foo::FOO } ",
        );
        check_assist_not_applicable(
            change_visibility,
            r"mod foo { pub static FOO: () = (); }
              fn main() { foo::FOO<|> } ",
        );
    }

    #[test]
    fn change_visibility_of_trait_via_path() {
        check_assist(
            change_visibility,
            r"mod foo { trait Foo { fn foo(&self) {} } }
              fn main() { let x: &dyn foo::<|>Foo; } ",
            r"mod foo { <|>pub(crate) trait Foo { fn foo(&self) {} } }
              fn main() { let x: &dyn foo::Foo; } ",
        );
        check_assist_not_applicable(
            change_visibility,
            r"mod foo { pub trait Foo { fn foo(&self) {} } }
              fn main() { let x: &dyn foo::Foo<|>; } ",
        );
    }

    #[test]
    fn change_visibility_of_type_alias_via_path() {
        check_assist(
            change_visibility,
            r"mod foo { type Foo = (); }
              fn main() { let x: foo::Foo<|>; } ",
            r"mod foo { <|>pub(crate) type Foo = (); }
              fn main() { let x: foo::Foo; } ",
        );
        check_assist_not_applicable(
            change_visibility,
            r"mod foo { pub type Foo = (); }
              fn main() { let x: foo::Foo<|>; } ",
        );
    }

    #[test]
    fn change_visibility_of_module_via_path() {
        check_assist(
            change_visibility,
            r"mod foo { mod bar { fn bar() {} } }
              fn main() { foo::bar<|>::bar(); } ",
            r"mod foo { <|>pub(crate) mod bar { fn bar() {} } }
              fn main() { foo::bar::bar(); } ",
        );

        check_assist(
            change_visibility,
            r"
            //- /main.rs
            mod foo;
            fn main() { foo::bar<|>::baz(); }

            //- /foo.rs
            mod bar {
                pub fn baz() {}
            }
            ",
            r"<|>pub(crate) mod bar {
    pub fn baz() {}
}

",
        );

        check_assist_not_applicable(
            change_visibility,
            r"mod foo { pub mod bar { pub fn bar() {} } }
              fn main() { foo::bar<|>::bar(); } ",
        );
    }

    #[test]
    fn change_visibility_of_inline_module_in_other_file_via_path() {
        check_assist(
            change_visibility,
            r"
            //- /main.rs
            mod foo;
            fn main() { foo::bar<|>::baz(); }

            //- /foo.rs
            mod bar;

            //- /foo/bar.rs
            pub fn baz() {}
            }
            ",
            r"<|>pub(crate) mod bar;
",
        );
    }

    #[test]
    fn change_visibility_of_module_declaration_in_other_file_via_path() {
        check_assist(
            change_visibility,
            r"
            //- /main.rs
            mod foo;
            fn main() { foo::bar<|>>::baz(); }

            //- /foo.rs
            mod bar {
                pub fn baz() {}
            }
            ",
            r"<|>pub(crate) mod bar {
    pub fn baz() {}
}

",
        );
    }

    #[test]
    fn change_visibility_target() {
        check_assist_target(change_visibility, "<|>fn foo() {}", "fn");
        check_assist_target(change_visibility, "pub(crate)<|> fn foo() {}", "pub(crate)");
        check_assist_target(change_visibility, "struct S { <|>field: u32 }", "field");
    }
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2016-2017, Robert Ou <rqou@robertou.com> and contributors
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//! Tool that converts a jed to a json file

use std::cell::RefCell;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;

extern crate xc2bit;
use xc2bit::*;

extern crate yosys_netlist_json;
use yosys_netlist_json::*;

fn main() {
    let args = ::std::env::args().collect::<Vec<_>>();

    if args.len() != 2 {
        println!("Usage: {} file.jed", args[0]);
        ::std::process::exit(1);
    }

    // Load the jed
    let mut f = File::open(&args[1]).expect("failed to open file");
    let mut data = Vec::new();
    f.read_to_end(&mut data).expect("failed to read data");

    let bits_result = read_jed(&data);
    let (bits, device_name_option) = bits_result.expect("failed to read jed");
    let device_name = device_name_option.expect("missing device name in jed");

    let bitstream_result = XC2Bitstream::from_jed(&bits, &device_name);
    let bitstream = bitstream_result.expect("failed to process jed");

    // Because of how the closures work, we unfortunately need to use a RefCell here
    let output_netlist = RefCell::new(Netlist::default());
    let node_vec = RefCell::new(Vec::new());
    let wire_vec = RefCell::new(Vec::new());

    // Create common/global stuff ahead of time
    {
        let mut output_netlist_mut = output_netlist.borrow_mut();
        // TOOD: Proper version number
        output_netlist_mut.creator = String::from("xc2bit xc2jed2json utility - DEVELOPMENT VERSION");

        let mut module = Module::default();
        module.attributes.insert(String::from("PART_NAME"),
            AttributeVal::S(format!("{}", bitstream.bits.device_type())));
        module.attributes.insert(String::from("PART_SPEED"),
            AttributeVal::S(format!("{}", bitstream.speed_grade)));
        module.attributes.insert(String::from("PART_PKG"),
            AttributeVal::S(format!("{}", bitstream.package)));

        output_netlist_mut.modules.insert(String::from("top"), module);
    }

    // Call the giant structure callback
    get_device_structure(bitstream.bits.device_type(),
        |node_name: &str, node_type: &str, fb: u32, idx: u32| {
            // Memoization needed for the interface
            let mut node_vec = node_vec.borrow_mut();
            let i = node_vec.len();
            node_vec.push((node_name.to_owned(), node_type.to_owned(), fb, idx));
            i
        },
        |wire_name: &str| {
            // Memoization needed to convert wire names to numbers
            let mut wire_vec = wire_vec.borrow_mut();
            let i = wire_vec.len();
            wire_vec.push(wire_name.to_owned());

            // Create the net in the output module
            let mut output_netlist_mut = output_netlist.borrow_mut();
            let mut netnames = &mut output_netlist_mut.modules.get_mut("top").unwrap().netnames;
            netnames.insert(wire_name.to_owned(), Netname {
                hide_name: 0,
                bits: vec![BitVal::N(i + 2)],
                attributes: HashMap::default(),
            });

            i
        },
        |node_ref: usize, wire_ref: usize, port_name: &str, port_idx: u32| {
        }
    );

    // Write the final output
    output_netlist.borrow().to_writer(&mut ::std::io::stdout()).expect("failed to write json");
}
<commit_msg>xc2bit-jed2json: Begin outputting IO and BUFx cells<commit_after>/*
Copyright (c) 2016-2017, Robert Ou <rqou@robertou.com> and contributors
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//! Tool that converts a jed to a json file

use std::cell::RefCell;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;

extern crate xc2bit;
use xc2bit::*;

extern crate yosys_netlist_json;
use yosys_netlist_json::*;

fn main() {
    let args = ::std::env::args().collect::<Vec<_>>();

    if args.len() != 2 {
        println!("Usage: {} file.jed", args[0]);
        ::std::process::exit(1);
    }

    // Load the jed
    let mut f = File::open(&args[1]).expect("failed to open file");
    let mut data = Vec::new();
    f.read_to_end(&mut data).expect("failed to read data");

    let bits_result = read_jed(&data);
    let (bits, device_name_option) = bits_result.expect("failed to read jed");
    let device_name = device_name_option.expect("missing device name in jed");

    let bitstream_result = XC2Bitstream::from_jed(&bits, &device_name);
    let bitstream = bitstream_result.expect("failed to process jed");

    // Because of how the closures work, we unfortunately need to use a RefCell here
    let output_netlist = RefCell::new(Netlist::default());
    let node_vec = RefCell::new(Vec::new());
    // Skip 0 and 1 just like yosys does
    let wire_idx = RefCell::new(2);

    // Create common/global stuff ahead of time
    {
        let mut output_netlist_mut = output_netlist.borrow_mut();
        // TOOD: Proper version number
        output_netlist_mut.creator = String::from("xc2bit xc2jed2json utility - DEVELOPMENT VERSION");

        let mut module = Module::default();
        module.attributes.insert(String::from("PART_NAME"),
            AttributeVal::S(format!("{}", bitstream.bits.device_type())));
        module.attributes.insert(String::from("PART_SPEED"),
            AttributeVal::S(format!("{}", bitstream.speed_grade)));
        module.attributes.insert(String::from("PART_PKG"),
            AttributeVal::S(format!("{}", bitstream.package)));

        output_netlist_mut.modules.insert(String::from("top"), module);
    }

    // Call the giant structure callback
    get_device_structure(bitstream.bits.device_type(),
        |node_name: &str, node_type: &str, fb: u32, idx: u32| {
            // Start constructing the cell object
            let cell;

            match node_type {
                "BUFG" | "BUFGSR" | "BUFGTS" => {
                    let mut connections = HashMap::new();
                    connections.insert(String::from("I"), Vec::new());
                    connections.insert(String::from("O"), Vec::new());
                    cell = Cell {
                        hide_name: 0,
                        cell_type: node_type.to_owned(),
                        parameters: HashMap::new(),
                        attributes: HashMap::new(),
                        port_directions: HashMap::new(),
                        connections: connections,
                    }
                },
                "IOBUFE" => {
                    // Construct the wire for the toplevel port
                    let toplevel_wire = {
                        let orig_wire_idx = {*wire_idx.borrow()};
                        let mut output_netlist_mut = output_netlist.borrow_mut();
                        let mut netnames = &mut output_netlist_mut.modules.get_mut("top").unwrap().netnames;
                        netnames.insert(format!("PAD_{}", idx), Netname {
                            hide_name: 0,
                            bits: vec![BitVal::N(orig_wire_idx)],
                            attributes: HashMap::new(),
                        });

                        // Return the current wire index
                        *wire_idx.borrow_mut() += 1;
                        orig_wire_idx
                    };

                    // Construct the toplevel port
                    {
                        let mut output_netlist_mut = output_netlist.borrow_mut();
                        let mut ports = &mut output_netlist_mut.modules.get_mut("top").unwrap().ports;
                        ports.insert(format!("PAD_{}", idx), Port {
                            direction: PortDirection::InOut,
                            bits: vec![BitVal::N(toplevel_wire)],
                        });
                    }

                    let mut connections = HashMap::new();
                    connections.insert(String::from("I"), Vec::new());
                    connections.insert(String::from("E"), Vec::new());
                    connections.insert(String::from("O"), Vec::new());
                    connections.insert(String::from("IO"), vec![BitVal::N(toplevel_wire)]);
                    cell = Cell {
                        hide_name: 0,
                        cell_type: node_type.to_owned(),
                        parameters: HashMap::new(),
                        attributes: HashMap::new(),
                        port_directions: HashMap::new(),
                        connections: connections,
                    }
                },
                // FIXME: Boilerplate
                "IBUF" => {
                    // Construct the wire for the toplevel port
                    let toplevel_wire = {
                        let orig_wire_idx = {*wire_idx.borrow()};
                        let mut output_netlist_mut = output_netlist.borrow_mut();
                        let mut netnames = &mut output_netlist_mut.modules.get_mut("top").unwrap().netnames;
                        netnames.insert(String::from("INPAD"), Netname {
                            hide_name: 0,
                            bits: vec![BitVal::N(orig_wire_idx)],
                            attributes: HashMap::new(),
                        });

                        // Return the current wire index
                        *wire_idx.borrow_mut() += 1;
                        orig_wire_idx
                    };

                    // Construct the toplevel port
                    {
                        let mut output_netlist_mut = output_netlist.borrow_mut();
                        let mut ports = &mut output_netlist_mut.modules.get_mut("top").unwrap().ports;
                        ports.insert(String::from("INPAD"), Port {
                            direction: PortDirection::Input,
                            bits: vec![BitVal::N(toplevel_wire)],
                        });
                    }

                    let mut connections = HashMap::new();
                    connections.insert(String::from("O"), Vec::new());
                    connections.insert(String::from("I"), vec![BitVal::N(toplevel_wire)]);
                    cell = Cell {
                        hide_name: 0,
                        cell_type: node_type.to_owned(),
                        parameters: HashMap::new(),
                        attributes: HashMap::new(),
                        port_directions: HashMap::new(),
                        connections: connections,
                    }
                },
                _ => {
                    // FIXME
                    println!("{} is not implemented!", node_type);
                    cell = Cell {
                        hide_name: 0,
                        cell_type: String::from("FIXME FIXME FIXME"),
                        parameters: HashMap::new(),
                        attributes: HashMap::new(),
                        port_directions: HashMap::new(),
                        connections: HashMap::new(),
                    }
                },
            }

            // Create the cell in the output module
            let mut output_netlist_mut = output_netlist.borrow_mut();
            let mut cells = &mut output_netlist_mut.modules.get_mut("top").unwrap().cells;
            cells.insert(node_name.to_owned(), cell);

            // Memoization needed for the callback interface
            let mut node_vec = node_vec.borrow_mut();
            node_vec.push((node_name.to_owned(), node_type.to_owned(), fb, idx));
            node_vec.len() - 1
        },
        |wire_name: &str| {
            // Create the net in the output module
            let orig_wire_idx = {*wire_idx.borrow()};
            let mut output_netlist_mut = output_netlist.borrow_mut();
            let mut netnames = &mut output_netlist_mut.modules.get_mut("top").unwrap().netnames;
            netnames.insert(wire_name.to_owned(), Netname {
                hide_name: 0,
                bits: vec![BitVal::N(orig_wire_idx)],
                attributes: HashMap::new(),
            });

            // Return the current wire index
            *wire_idx.borrow_mut() += 1;
            orig_wire_idx
        },
        |node_ref: usize, wire_ref: usize, port_name: &str, port_idx: u32| {
        }
    );

    // Write the final output
    output_netlist.borrow().to_writer(&mut ::std::io::stdout()).expect("failed to write json");
}
<|endoftext|>


<commit_before>// Copyright (c) Facebook, Inc. and its affiliates
// SPDX-License-Identifier: MIT OR Apache-2.0

//! # Serde code generator
//!
//! '''bash
//! cargo run --bin serdegen -- --help
//! '''

use serde_generate::{
    cpp, csharp, golang, java, python3, rust, typescript, CodeGeneratorConfig, Encoding,
    SourceInstaller,
};
use serde_reflection::Registry;
use std::path::PathBuf;
use structopt::{clap::arg_enum, StructOpt};

arg_enum! {
#[derive(Debug, StructOpt)]
enum Language {
    Python3,
    Cpp,
    Rust,
    Java,
    Go,
    TypeScript,
    CSharp,
}
}

arg_enum! {
#[derive(Debug, StructOpt, PartialEq, Eq, PartialOrd, Ord)]
enum Runtime {
    Serde,
    Bincode,
    Lcs,
}
}

#[derive(Debug, StructOpt)]
#[structopt(
    name = "Serde code generator",
    about = "Generate code for Serde containers"
)]
struct Options {
    /// Path to the YAML-encoded Serde formats.
    #[structopt(parse(from_os_str))]
    input: Option<PathBuf>,

    /// Language for code generation.
    #[structopt(long, possible_values = &Language::variants(), case_insensitive = true, default_value = "Python3")]
    language: Language,

    /// Directory where to write generated modules (otherwise print code on stdout).
    #[structopt(long)]
    target_source_dir: Option<PathBuf>,

    /// Optional runtimes to install in the `target_source_dir` (if applicable).
    /// Also triggers the generation of specialized methods for each runtime.
    #[structopt(long, possible_values = &Runtime::variants(), case_insensitive = true)]
    with_runtimes: Vec<Runtime>,

    /// Module name for the Serde formats installed in the `target_source_dir`.
    /// Rust crates may contain a version number separated with a colon, e.g. "test:1.2.0".
    /// (By default, the installer will use version "0.1.0".)
    #[structopt(long)]
    module_name: Option<String>,

    /// Optional package name (Python) or module path (Go) where to find Serde runtime dependencies.
    #[structopt(long)]
    serde_package_name: Option<String>,
}

fn get_codegen_config<'a, I>(name: String, runtimes: I) -> CodeGeneratorConfig
where
    I: IntoIterator<Item = &'a Runtime>,
{
    let mut encodings = Vec::new();
    for runtime in runtimes {
        match runtime {
            Runtime::Bincode => {
                encodings.push(Encoding::Bincode);
            }
            Runtime::Lcs => {
                encodings.push(Encoding::Lcs);
            }
            _ => (),
        }
    }
    CodeGeneratorConfig::new(name).with_encodings(encodings)
}

fn main() {
    let options = Options::from_args();
    let serde_package_name_opt = options.serde_package_name.clone();
    let named_registry_opt = match &options.input {
        None => None,
        Some(input) => {
            let name = options.module_name.clone().unwrap_or_else(|| {
                input
                    .file_stem()
                    .expect("failed to deduce module name from input path")
                    .to_string_lossy()
                    .into_owned()
            });
            let content = std::fs::read_to_string(input).expect("input file must be readable");
            let registry = serde_yaml::from_str::<Registry>(content.as_str()).unwrap();
            Some((registry, name))
        }
    };
    let runtimes: std::collections::BTreeSet<_> = options.with_runtimes.into_iter().collect();

    match options.target_source_dir {
        None => {
            if let Some((registry, name)) = named_registry_opt {
                let config = get_codegen_config(name, &runtimes);

                let stdout = std::io::stdout();
                let mut out = stdout.lock();
                match options.language {
                    Language::Python3 => python3::CodeGenerator::new(&config)
                        .with_serde_package_name(serde_package_name_opt)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Rust => rust::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Cpp => cpp::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Go => golang::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Java => panic!("Code generation in Java requires `--install-dir`"),
                    Language::TypeScript => typescript::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::CSharp => panic!("Code generation in C# requires `--install-dir`"),
                }
            }
        }

        Some(install_dir) => {
            let installer: Box<dyn SourceInstaller<Error = Box<dyn std::error::Error>>> =
                match options.language {
                    Language::Python3 => {
                        Box::new(python3::Installer::new(install_dir, serde_package_name_opt))
                    }
                    Language::Rust => Box::new(rust::Installer::new(install_dir)),
                    Language::Cpp => Box::new(cpp::Installer::new(install_dir)),
                    Language::Java => Box::new(java::Installer::new(install_dir)),
                    Language::Go => {
                        Box::new(golang::Installer::new(install_dir, serde_package_name_opt))
                    }
                    Language::TypeScript => Box::new(typescript::Installer::new(install_dir)),
                    Language::CSharp => Box::new(csharp::Installer::new(install_dir)),
                };

            if let Some((registry, name)) = named_registry_opt {
                let config = get_codegen_config(name, &runtimes);
                installer.install_module(&config, &registry).unwrap();
            }

            for runtime in runtimes {
                match runtime {
                    Runtime::Serde => installer.install_serde_runtime().unwrap(),
                    Runtime::Bincode => installer.install_bincode_runtime().unwrap(),
                    Runtime::Lcs => installer.install_lcs_runtime().unwrap(),
                }
            }
        }
    }
}
<commit_msg>serdegen: Add --c-style-enums argument<commit_after>// Copyright (c) Facebook, Inc. and its affiliates
// SPDX-License-Identifier: MIT OR Apache-2.0

//! # Serde code generator
//!
//! '''bash
//! cargo run --bin serdegen -- --help
//! '''

use serde_generate::{
    cpp, csharp, golang, java, python3, rust, typescript, CodeGeneratorConfig, Encoding,
    SourceInstaller,
};
use serde_reflection::Registry;
use std::path::PathBuf;
use structopt::{clap::arg_enum, StructOpt};

arg_enum! {
#[derive(Debug, StructOpt)]
enum Language {
    Python3,
    Cpp,
    Rust,
    Java,
    Go,
    TypeScript,
    CSharp,
}
}

arg_enum! {
#[derive(Debug, StructOpt, PartialEq, Eq, PartialOrd, Ord)]
enum Runtime {
    Serde,
    Bincode,
    Lcs,
}
}

#[derive(Debug, StructOpt)]
#[structopt(
    name = "Serde code generator",
    about = "Generate code for Serde containers"
)]
struct Options {
    /// Path to the YAML-encoded Serde formats.
    #[structopt(parse(from_os_str))]
    input: Option<PathBuf>,

    /// Language for code generation.
    #[structopt(long, possible_values = &Language::variants(), case_insensitive = true, default_value = "Python3")]
    language: Language,

    /// Directory where to write generated modules (otherwise print code on stdout).
    #[structopt(long)]
    target_source_dir: Option<PathBuf>,

    /// Optional runtimes to install in the `target_source_dir` (if applicable).
    /// Also triggers the generation of specialized methods for each runtime.
    #[structopt(long, possible_values = &Runtime::variants(), case_insensitive = true)]
    with_runtimes: Vec<Runtime>,

    /// Module name for the Serde formats installed in the `target_source_dir`.
    /// Rust crates may contain a version number separated with a colon, e.g. "test:1.2.0".
    /// (By default, the installer will use version "0.1.0".)
    #[structopt(long)]
    module_name: Option<String>,

    /// Optional package name (Python) or module path (Go) where to find Serde runtime dependencies.
    #[structopt(long)]
    serde_package_name: Option<String>,

    /// Translate enums without variant data (c-style enums) into their equivalent in the target language.
    #[structopt(long)]
    c_style_enums: bool,
}

fn get_codegen_config<'a, I>(name: String, runtimes: I, c_style_enums: bool) -> CodeGeneratorConfig
where
    I: IntoIterator<Item = &'a Runtime>,
{
    let mut encodings = Vec::new();
    for runtime in runtimes {
        match runtime {
            Runtime::Bincode => {
                encodings.push(Encoding::Bincode);
            }
            Runtime::Lcs => {
                encodings.push(Encoding::Lcs);
            }
            _ => (),
        }
    }
    CodeGeneratorConfig::new(name)
        .with_encodings(encodings)
        .with_c_style_enums(c_style_enums)
}

fn main() {
    let options = Options::from_args();
    let serde_package_name_opt = options.serde_package_name.clone();
    let named_registry_opt = match &options.input {
        None => None,
        Some(input) => {
            let name = options.module_name.clone().unwrap_or_else(|| {
                input
                    .file_stem()
                    .expect("failed to deduce module name from input path")
                    .to_string_lossy()
                    .into_owned()
            });
            let content = std::fs::read_to_string(input).expect("input file must be readable");
            let registry = serde_yaml::from_str::<Registry>(content.as_str()).unwrap();
            Some((registry, name))
        }
    };
    let runtimes: std::collections::BTreeSet<_> = options.with_runtimes.into_iter().collect();

    match options.target_source_dir {
        None => {
            if let Some((registry, name)) = named_registry_opt {
                let config = get_codegen_config(name, &runtimes, options.c_style_enums);

                let stdout = std::io::stdout();
                let mut out = stdout.lock();
                match options.language {
                    Language::Python3 => python3::CodeGenerator::new(&config)
                        .with_serde_package_name(serde_package_name_opt)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Rust => rust::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Cpp => cpp::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Go => golang::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Java => panic!("Code generation in Java requires `--install-dir`"),
                    Language::TypeScript => typescript::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::CSharp => panic!("Code generation in C# requires `--install-dir`"),
                }
            }
        }

        Some(install_dir) => {
            let installer: Box<dyn SourceInstaller<Error = Box<dyn std::error::Error>>> =
                match options.language {
                    Language::Python3 => {
                        Box::new(python3::Installer::new(install_dir, serde_package_name_opt))
                    }
                    Language::Rust => Box::new(rust::Installer::new(install_dir)),
                    Language::Cpp => Box::new(cpp::Installer::new(install_dir)),
                    Language::Java => Box::new(java::Installer::new(install_dir)),
                    Language::Go => {
                        Box::new(golang::Installer::new(install_dir, serde_package_name_opt))
                    }
                    Language::TypeScript => Box::new(typescript::Installer::new(install_dir)),
                    Language::CSharp => Box::new(csharp::Installer::new(install_dir)),
                };

            if let Some((registry, name)) = named_registry_opt {
                let config = get_codegen_config(name, &runtimes, options.c_style_enums);
                installer.install_module(&config, &registry).unwrap();
            }

            for runtime in runtimes {
                match runtime {
                    Runtime::Serde => installer.install_serde_runtime().unwrap(),
                    Runtime::Bincode => installer.install_bincode_runtime().unwrap(),
                    Runtime::Lcs => installer.install_lcs_runtime().unwrap(),
                }
            }
        }
    }
}
<|endoftext|>