<commit_before>//! This module generates [moniker](https://microsoft.github.io/language-server-protocol/specifications/lsif/0.6.0/specification/#exportsImports)
//! for LSIF and LSP.

use hir::{db::DefDatabase, Crate, Name, Semantics};
use ide_db::{
    base_db::{CrateOrigin, FileId, FileLoader, FilePosition},
    defs::Definition,
    helpers::pick_best_token,
    RootDatabase,
};
use itertools::Itertools;
use syntax::{AstNode, SyntaxKind::*, T};

use crate::{doc_links::token_as_doc_comment, RangeInfo};

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MonikerIdentifier {
    crate_name: String,
    path: Vec<Name>,
}

impl ToString for MonikerIdentifier {
    fn to_string(&self) -> String {
        match self {
            MonikerIdentifier { path, crate_name } => {
                format!("{}::{}", crate_name, path.iter().map(|x| x.to_string()).join("::"))
            }
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum MonikerKind {
    Import,
    Export,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MonikerResult {
    pub identifier: MonikerIdentifier,
    pub kind: MonikerKind,
    pub package_information: PackageInformation,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PackageInformation {
    pub name: String,
    pub repo: String,
    pub version: String,
}

pub(crate) fn crate_for_file(db: &RootDatabase, file_id: FileId) -> Option<Crate> {
    for &krate in db.relevant_crates(file_id).iter() {
        let crate_def_map = db.crate_def_map(krate);
        for (_, data) in crate_def_map.modules() {
            if data.origin.file_id() == Some(file_id) {
                return Some(krate.into());
            }
        }
    }
    None
}

pub(crate) fn moniker(
    db: &RootDatabase,
    FilePosition { file_id, offset }: FilePosition,
) -> Option<RangeInfo<Vec<MonikerResult>>> {
    let sema = &Semantics::new(db);
    let file = sema.parse(file_id).syntax().clone();
    let current_crate = crate_for_file(db, file_id)?;
    let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
        IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | COMMENT => 2,
        kind if kind.is_trivia() => 0,
        _ => 1,
    })?;
    if let Some(doc_comment) = token_as_doc_comment(&original_token) {
        return doc_comment.get_definition_with_descend_at(sema, offset, |def, _, _| {
            let m = def_to_moniker(db, def, current_crate)?;
            Some(RangeInfo::new(original_token.text_range(), vec![m]))
        });
    }
    let navs = sema
        .descend_into_macros(original_token.clone())
        .into_iter()
        .map(|token| {
            Definition::from_token(sema, &token)
                .into_iter()
                .flat_map(|def| def_to_moniker(sema.db, def, current_crate))
                .collect::<Vec<_>>()
        })
        .flatten()
        .unique()
        .collect::<Vec<_>>();
    Some(RangeInfo::new(original_token.text_range(), navs))
}

pub(crate) fn def_to_moniker(
    db: &RootDatabase,
    def: Definition,
    from_crate: Crate,
) -> Option<MonikerResult> {
    if matches!(def, Definition::GenericParam(_) | Definition::SelfType(_) | Definition::Local(_)) {
        return None;
    }
    let module = def.module(db)?;
    let krate = module.krate();
    let mut path = vec![];
    path.extend(module.path_to_root(db).into_iter().filter_map(|x| x.name(db)));
    if let Definition::Field(it) = def {
        path.push(it.parent_def(db).name(db));
    }
    path.push(def.name(db)?);
    Some(MonikerResult {
        identifier: MonikerIdentifier {
            crate_name: krate.display_name(db)?.crate_name().to_string(),
            path,
        },
        kind: if krate == from_crate { MonikerKind::Export } else { MonikerKind::Import },
        package_information: {
            let name = krate.display_name(db)?.to_string();
            let (repo, version) = match krate.origin(db) {
                CrateOrigin::CratesIo { repo } => (repo?, krate.version(db)?),
                CrateOrigin::Lang => (
                    "https://github.com/rust-lang/rust/".to_string(),
                    "compiler_version".to_string(),
                ),
                CrateOrigin::Unknown => return None,
            };
            PackageInformation { name, repo, version }
        },
    })
}

#[cfg(test)]
mod tests {
    use crate::fixture;

    use super::MonikerKind;

    #[track_caller]
    fn no_moniker(ra_fixture: &str) {
        let (analysis, position) = fixture::position(ra_fixture);
        if let Some(x) = analysis.moniker(position).unwrap() {
            assert_eq!(x.info.len(), 0, "Moniker founded but no moniker expected: {:?}", x);
        }
    }

    #[track_caller]
    fn check_moniker(ra_fixture: &str, identifier: &str, package: &str, kind: MonikerKind) {
        let (analysis, position) = fixture::position(ra_fixture);
        let x = analysis.moniker(position).unwrap().expect("no moniker found").info;
        assert_eq!(x.len(), 1);
        let x = x.into_iter().next().unwrap();
        assert_eq!(identifier, x.identifier.to_string());
        assert_eq!(package, format!("{:?}", x.package_information));
        assert_eq!(kind, x.kind);
    }

    #[test]
    fn basic() {
        check_moniker(
            r#"
//- /lib.rs crate:main deps:foo
use foo::module::func;
fn main() {
    func$0();
}
//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
pub mod module {
    pub fn func() {}
}
"#,
            "foo::module::func",
            r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#,
            MonikerKind::Import,
        );
        check_moniker(
            r#"
//- /lib.rs crate:main deps:foo
use foo::module::func;
fn main() {
    func();
}
//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
pub mod module {
    pub fn func$0() {}
}
"#,
            "foo::module::func",
            r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#,
            MonikerKind::Export,
        );
    }

    #[test]
    fn moniker_for_field() {
        check_moniker(
            r#"
//- /lib.rs crate:main deps:foo
use foo::St;
fn main() {
    let x = St { a$0: 2 };
}
//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
pub struct St {
    pub a: i32,
}
"#,
            "foo::St::a",
            r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#,
            MonikerKind::Import,
        );
    }

    #[test]
    fn no_moniker_for_local() {
        no_moniker(
            r#"
//- /lib.rs crate:main deps:foo
use foo::module::func;
fn main() {
    func();
}
//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
pub mod module {
    pub fn func() {
        let x$0 = 2;
    }
}
"#,
        );
    }
}
<commit_msg>fix: emit trait names in moniker identifier<commit_after>//! This module generates [moniker](https://microsoft.github.io/language-server-protocol/specifications/lsif/0.6.0/specification/#exportsImports)
//! for LSIF and LSP.

use hir::{db::DefDatabase, AsAssocItem, AssocItemContainer, Crate, Name, Semantics};
use ide_db::{
    base_db::{CrateOrigin, FileId, FileLoader, FilePosition},
    defs::Definition,
    helpers::pick_best_token,
    RootDatabase,
};
use itertools::Itertools;
use syntax::{AstNode, SyntaxKind::*, T};

use crate::{doc_links::token_as_doc_comment, RangeInfo};

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MonikerIdentifier {
    crate_name: String,
    path: Vec<Name>,
}

impl ToString for MonikerIdentifier {
    fn to_string(&self) -> String {
        match self {
            MonikerIdentifier { path, crate_name } => {
                format!("{}::{}", crate_name, path.iter().map(|x| x.to_string()).join("::"))
            }
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum MonikerKind {
    Import,
    Export,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MonikerResult {
    pub identifier: MonikerIdentifier,
    pub kind: MonikerKind,
    pub package_information: PackageInformation,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PackageInformation {
    pub name: String,
    pub repo: String,
    pub version: String,
}

pub(crate) fn crate_for_file(db: &RootDatabase, file_id: FileId) -> Option<Crate> {
    for &krate in db.relevant_crates(file_id).iter() {
        let crate_def_map = db.crate_def_map(krate);
        for (_, data) in crate_def_map.modules() {
            if data.origin.file_id() == Some(file_id) {
                return Some(krate.into());
            }
        }
    }
    None
}

pub(crate) fn moniker(
    db: &RootDatabase,
    FilePosition { file_id, offset }: FilePosition,
) -> Option<RangeInfo<Vec<MonikerResult>>> {
    let sema = &Semantics::new(db);
    let file = sema.parse(file_id).syntax().clone();
    let current_crate = crate_for_file(db, file_id)?;
    let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
        IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | COMMENT => 2,
        kind if kind.is_trivia() => 0,
        _ => 1,
    })?;
    if let Some(doc_comment) = token_as_doc_comment(&original_token) {
        return doc_comment.get_definition_with_descend_at(sema, offset, |def, _, _| {
            let m = def_to_moniker(db, def, current_crate)?;
            Some(RangeInfo::new(original_token.text_range(), vec![m]))
        });
    }
    let navs = sema
        .descend_into_macros(original_token.clone())
        .into_iter()
        .map(|token| {
            Definition::from_token(sema, &token)
                .into_iter()
                .flat_map(|def| def_to_moniker(sema.db, def, current_crate))
                .collect::<Vec<_>>()
        })
        .flatten()
        .unique()
        .collect::<Vec<_>>();
    Some(RangeInfo::new(original_token.text_range(), navs))
}

pub(crate) fn def_to_moniker(
    db: &RootDatabase,
    def: Definition,
    from_crate: Crate,
) -> Option<MonikerResult> {
    if matches!(def, Definition::GenericParam(_) | Definition::SelfType(_) | Definition::Local(_)) {
        return None;
    }
    let module = def.module(db)?;
    let krate = module.krate();
    let mut path = vec![];
    path.extend(module.path_to_root(db).into_iter().filter_map(|x| x.name(db)));

    match def {
        Definition::Field(it) => path.push(it.parent_def(db).name(db)),
        Definition::Function(it) => {
            // Ensure that trait functions are properly namespaced with the trait name
            if let Some(assoc) = it.as_assoc_item(db) {
                let container = assoc.container(db);
                if let AssocItemContainer::Trait(parent_trait) = container {
                    path.push(parent_trait.name(db));
                }
            }
        }
        _ => (),
    }

    path.push(def.name(db)?);
    Some(MonikerResult {
        identifier: MonikerIdentifier {
            crate_name: krate.display_name(db)?.crate_name().to_string(),
            path,
        },
        kind: if krate == from_crate { MonikerKind::Export } else { MonikerKind::Import },
        package_information: {
            let name = krate.display_name(db)?.to_string();
            let (repo, version) = match krate.origin(db) {
                CrateOrigin::CratesIo { repo } => (repo?, krate.version(db)?),
                CrateOrigin::Lang => (
                    "https://github.com/rust-lang/rust/".to_string(),
                    "compiler_version".to_string(),
                ),
                CrateOrigin::Unknown => return None,
            };
            PackageInformation { name, repo, version }
        },
    })
}

#[cfg(test)]
mod tests {
    use crate::fixture;

    use super::MonikerKind;

    #[track_caller]
    fn no_moniker(ra_fixture: &str) {
        let (analysis, position) = fixture::position(ra_fixture);
        if let Some(x) = analysis.moniker(position).unwrap() {
            assert_eq!(x.info.len(), 0, "Moniker founded but no moniker expected: {:?}", x);
        }
    }

    #[track_caller]
    fn check_moniker(ra_fixture: &str, identifier: &str, package: &str, kind: MonikerKind) {
        let (analysis, position) = fixture::position(ra_fixture);
        let x = analysis.moniker(position).unwrap().expect("no moniker found").info;
        assert_eq!(x.len(), 1);
        let x = x.into_iter().next().unwrap();
        assert_eq!(identifier, x.identifier.to_string());
        assert_eq!(package, format!("{:?}", x.package_information));
        assert_eq!(kind, x.kind);
    }

    #[test]
    fn basic() {
        check_moniker(
            r#"
//- /lib.rs crate:main deps:foo
use foo::module::func;
fn main() {
    func$0();
}
//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
pub mod module {
    pub fn func() {}
}
"#,
            "foo::module::func",
            r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#,
            MonikerKind::Import,
        );
        check_moniker(
            r#"
//- /lib.rs crate:main deps:foo
use foo::module::func;
fn main() {
    func();
}
//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
pub mod module {
    pub fn func$0() {}
}
"#,
            "foo::module::func",
            r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#,
            MonikerKind::Export,
        );
    }

    #[test]
    fn moniker_for_trait() {
        check_moniker(
            r#"
//- /lib.rs crate:main deps:foo
use foo::module::func;
fn main() {
    func();
}
//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
pub mod module {
    pub trait MyTrait {
        pub fn func$0() {}
    }
}
"#,
            "foo::module::MyTrait::func",
            r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#,
            MonikerKind::Export,
        );
        check_moniker(
            r#"
//- /lib.rs crate:main deps:foo
use foo::module::func;
fn main() {
    func();
}
//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
pub mod module {
    pub fn func$0() {}
}
"#,
            "foo::module::func",
            r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#,
            MonikerKind::Export,
        );
    }

    #[test]
    fn moniker_for_field() {
        check_moniker(
            r#"
//- /lib.rs crate:main deps:foo
use foo::St;
fn main() {
    let x = St { a$0: 2 };
}
//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
pub struct St {
    pub a: i32,
}
"#,
            "foo::St::a",
            r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#,
            MonikerKind::Import,
        );
    }

    #[test]
    fn no_moniker_for_local() {
        no_moniker(
            r#"
//- /lib.rs crate:main deps:foo
use foo::module::func;
fn main() {
    func();
}
//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
pub mod module {
    pub fn func() {
        let x$0 = 2;
    }
}
"#,
        );
    }
}
<|endoftext|>


<commit_before>use std::fmt;

use crate::KString;
use crate::KStringRef;
use crate::KStringRefInner;

type StdString = std::string::String;
type BoxedStr = Box<str>;

/// A reference to a UTF-8 encoded, immutable string.
#[derive(Clone, Debug)]
#[repr(transparent)]
pub struct KStringCow<'s> {
    pub(crate) inner: KStringCowInner<'s>,
}

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) enum KStringCowInner<'s> {
    Owned(KString),
    Borrowed(&'s str),
}

impl<'s> KStringCow<'s> {
    /// Create a new empty `KStringCow`.
    #[inline]
    pub fn new() -> Self {
        Default::default()
    }

    /// Create an owned `KStringCow`.
    #[inline]
    pub fn from_boxed(other: BoxedStr) -> Self {
        Self {
            inner: KStringCowInner::Owned(KString::from_boxed(other)),
        }
    }

    /// Create an owned `KStringCow`.
    #[inline]
    pub fn from_string(other: StdString) -> Self {
        Self::from_boxed(other.into_boxed_str())
    }

    /// Create a reference to a borrowed data.
    #[inline]
    pub fn from_ref(other: &'s str) -> Self {
        Self {
            inner: KStringCowInner::Borrowed(other),
        }
    }

    /// Create a reference to a `'static` data.
    #[inline]
    pub fn from_static(other: &'static str) -> Self {
        Self {
            inner: KStringCowInner::Owned(KString::from_static(other)),
        }
    }

    /// Get a reference to the `KString`.
    #[inline]
    pub fn as_ref(&self) -> KStringRef<'_> {
        self.inner.as_ref()
    }

    /// Clone the data into an owned-type.
    #[inline]
    pub fn into_owned(self) -> KString {
        self.inner.into_owned()
    }

    /// Extracts a string slice containing the entire `KStringCow`.
    #[inline]
    pub fn as_str(&self) -> &str {
        self.inner.as_str()
    }

    /// Convert to a mutable string type, cloning the data if necessary.
    #[inline]
    pub fn into_string(self) -> StdString {
        String::from(self.into_boxed_str())
    }

    /// Convert to a mutable string type, cloning the data if necessary.
    #[inline]
    pub fn into_boxed_str(self) -> BoxedStr {
        self.inner.into_boxed_str()
    }
}

impl<'s> KStringCowInner<'s> {
    #[inline]
    fn as_ref(&self) -> KStringRef<'_> {
        match self {
            Self::Owned(ref s) => s.as_ref(),
            Self::Borrowed(ref s) => KStringRef::from_ref(s),
        }
    }

    #[inline]
    fn into_owned(self) -> KString {
        match self {
            Self::Owned(s) => s,
            Self::Borrowed(s) => KString::from_ref(s),
        }
    }

    #[inline]
    fn as_str(&self) -> &str {
        match self {
            Self::Owned(ref s) => s.as_str(),
            Self::Borrowed(ref s) => s,
        }
    }

    #[inline]
    fn into_boxed_str(self) -> BoxedStr {
        match self {
            Self::Owned(s) => s.into_boxed_str(),
            Self::Borrowed(s) => BoxedStr::from(s),
        }
    }
}

impl<'s> std::ops::Deref for KStringCow<'s> {
    type Target = str;

    #[inline]
    fn deref(&self) -> &str {
        self.as_str()
    }
}

impl<'s> Eq for KStringCow<'s> {}

impl<'s> PartialEq<KStringCow<'s>> for KStringCow<'s> {
    #[inline]
    fn eq(&self, other: &KStringCow<'s>) -> bool {
        PartialEq::eq(self.as_str(), other.as_str())
    }
}

impl<'s> PartialEq<str> for KStringCow<'s> {
    #[inline]
    fn eq(&self, other: &str) -> bool {
        PartialEq::eq(self.as_str(), other)
    }
}

impl<'s> PartialEq<&'s str> for KStringCow<'s> {
    #[inline]
    fn eq(&self, other: &&str) -> bool {
        PartialEq::eq(self.as_str(), *other)
    }
}

impl<'s> PartialEq<String> for KStringCow<'s> {
    #[inline]
    fn eq(&self, other: &StdString) -> bool {
        PartialEq::eq(self.as_str(), other.as_str())
    }
}

impl<'s> Ord for KStringCow<'s> {
    #[inline]
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.as_str().cmp(other.as_str())
    }
}

impl<'s> PartialOrd for KStringCow<'s> {
    #[inline]
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        self.as_str().partial_cmp(other.as_str())
    }
}

impl<'s> std::hash::Hash for KStringCow<'s> {
    #[inline]
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.as_str().hash(state);
    }
}

impl<'s> fmt::Display for KStringCow<'s> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self.as_str(), f)
    }
}

impl<'s> AsRef<str> for KStringCow<'s> {
    #[inline]
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl<'s> AsRef<[u8]> for KStringCow<'s> {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl<'s> AsRef<std::ffi::OsStr> for KStringCow<'s> {
    #[inline]
    fn as_ref(&self) -> &std::ffi::OsStr {
        (&**self).as_ref()
    }
}

impl<'s> AsRef<std::path::Path> for KStringCow<'s> {
    #[inline]
    fn as_ref(&self) -> &std::path::Path {
        std::path::Path::new(self)
    }
}

impl<'s> std::borrow::Borrow<str> for KStringCow<'s> {
    #[inline]
    fn borrow(&self) -> &str {
        self.as_str()
    }
}

impl<'s> Default for KStringCow<'s> {
    #[inline]
    fn default() -> Self {
        Self::from_static("")
    }
}

impl From<KString> for KStringCow<'static> {
    #[inline]
    fn from(other: KString) -> Self {
        let inner = KStringCowInner::Owned(other);
        Self { inner }
    }
}

impl<'s> From<KStringRef<'s>> for KStringCow<'s> {
    #[inline]
    fn from(other: KStringRef<'s>) -> Self {
        match other.inner {
            KStringRefInner::Borrowed(s) => Self::from_ref(s),
            KStringRefInner::Singleton(s) => Self::from_static(s),
        }
    }
}

impl<'s> From<&'s KStringRef<'s>> for KStringCow<'s> {
    #[inline]
    fn from(other: &'s KStringRef<'s>) -> Self {
        match other.inner {
            KStringRefInner::Borrowed(s) => Self::from_ref(s),
            KStringRefInner::Singleton(s) => Self::from_static(s),
        }
    }
}

impl From<StdString> for KStringCow<'static> {
    #[inline]
    fn from(other: StdString) -> Self {
        // Since the memory is already allocated, don't bother moving it into a FixedString
        Self::from_boxed(other.into_boxed_str())
    }
}

impl<'s> From<&'s StdString> for KStringCow<'s> {
    #[inline]
    fn from(other: &'s StdString) -> Self {
        Self::from_ref(other.as_str())
    }
}

impl From<BoxedStr> for KStringCow<'static> {
    #[inline]
    fn from(other: BoxedStr) -> Self {
        // Since the memory is already allocated, don't bother moving it into a FixedString
        Self::from_boxed(other)
    }
}

impl<'s> From<&'s BoxedStr> for KStringCow<'s> {
    #[inline]
    fn from(other: &'s BoxedStr) -> Self {
        Self::from_ref(other)
    }
}

impl<'s> From<&'s str> for KStringCow<'s> {
    #[inline]
    fn from(other: &'s str) -> Self {
        Self::from_ref(other)
    }
}

impl<'s> serde::Serialize for KStringCow<'s> {
    #[inline]
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        serializer.serialize_str(self.as_str())
    }
}

impl<'de, 's> serde::Deserialize<'de> for KStringCow<'s> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        use std::borrow::Cow;
        let s: Cow<'_, str> = Cow::deserialize(deserializer)?;
        let s = match s {
            Cow::Owned(s) => KStringCow::from_boxed(s.into_boxed_str()),
            Cow::Borrowed(s) => KStringCow::from_ref(s),
        };
        Ok(s)
    }
}

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

    #[test]
    fn test_size() {
        println!(
            "Cow: {}",
            std::mem::size_of::<std::borrow::Cow<'static, str>>()
        );
        println!("KStringCow: {}", std::mem::size_of::<KStringCow<'static>>());
    }
}
<commit_msg>feat(kstring): Add an additional From<commit_after>use std::fmt;

use crate::KString;
use crate::KStringRef;
use crate::KStringRefInner;

type StdString = std::string::String;
type BoxedStr = Box<str>;

/// A reference to a UTF-8 encoded, immutable string.
#[derive(Clone, Debug)]
#[repr(transparent)]
pub struct KStringCow<'s> {
    pub(crate) inner: KStringCowInner<'s>,
}

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) enum KStringCowInner<'s> {
    Owned(KString),
    Borrowed(&'s str),
}

impl<'s> KStringCow<'s> {
    /// Create a new empty `KStringCow`.
    #[inline]
    pub fn new() -> Self {
        Default::default()
    }

    /// Create an owned `KStringCow`.
    #[inline]
    pub fn from_boxed(other: BoxedStr) -> Self {
        Self {
            inner: KStringCowInner::Owned(KString::from_boxed(other)),
        }
    }

    /// Create an owned `KStringCow`.
    #[inline]
    pub fn from_string(other: StdString) -> Self {
        Self::from_boxed(other.into_boxed_str())
    }

    /// Create a reference to a borrowed data.
    #[inline]
    pub fn from_ref(other: &'s str) -> Self {
        Self {
            inner: KStringCowInner::Borrowed(other),
        }
    }

    /// Create a reference to a `'static` data.
    #[inline]
    pub fn from_static(other: &'static str) -> Self {
        Self {
            inner: KStringCowInner::Owned(KString::from_static(other)),
        }
    }

    /// Get a reference to the `KString`.
    #[inline]
    pub fn as_ref(&self) -> KStringRef<'_> {
        self.inner.as_ref()
    }

    /// Clone the data into an owned-type.
    #[inline]
    pub fn into_owned(self) -> KString {
        self.inner.into_owned()
    }

    /// Extracts a string slice containing the entire `KStringCow`.
    #[inline]
    pub fn as_str(&self) -> &str {
        self.inner.as_str()
    }

    /// Convert to a mutable string type, cloning the data if necessary.
    #[inline]
    pub fn into_string(self) -> StdString {
        String::from(self.into_boxed_str())
    }

    /// Convert to a mutable string type, cloning the data if necessary.
    #[inline]
    pub fn into_boxed_str(self) -> BoxedStr {
        self.inner.into_boxed_str()
    }
}

impl<'s> KStringCowInner<'s> {
    #[inline]
    fn as_ref(&self) -> KStringRef<'_> {
        match self {
            Self::Owned(ref s) => s.as_ref(),
            Self::Borrowed(ref s) => KStringRef::from_ref(s),
        }
    }

    #[inline]
    fn into_owned(self) -> KString {
        match self {
            Self::Owned(s) => s,
            Self::Borrowed(s) => KString::from_ref(s),
        }
    }

    #[inline]
    fn as_str(&self) -> &str {
        match self {
            Self::Owned(ref s) => s.as_str(),
            Self::Borrowed(ref s) => s,
        }
    }

    #[inline]
    fn into_boxed_str(self) -> BoxedStr {
        match self {
            Self::Owned(s) => s.into_boxed_str(),
            Self::Borrowed(s) => BoxedStr::from(s),
        }
    }
}

impl<'s> std::ops::Deref for KStringCow<'s> {
    type Target = str;

    #[inline]
    fn deref(&self) -> &str {
        self.as_str()
    }
}

impl<'s> Eq for KStringCow<'s> {}

impl<'s> PartialEq<KStringCow<'s>> for KStringCow<'s> {
    #[inline]
    fn eq(&self, other: &KStringCow<'s>) -> bool {
        PartialEq::eq(self.as_str(), other.as_str())
    }
}

impl<'s> PartialEq<str> for KStringCow<'s> {
    #[inline]
    fn eq(&self, other: &str) -> bool {
        PartialEq::eq(self.as_str(), other)
    }
}

impl<'s> PartialEq<&'s str> for KStringCow<'s> {
    #[inline]
    fn eq(&self, other: &&str) -> bool {
        PartialEq::eq(self.as_str(), *other)
    }
}

impl<'s> PartialEq<String> for KStringCow<'s> {
    #[inline]
    fn eq(&self, other: &StdString) -> bool {
        PartialEq::eq(self.as_str(), other.as_str())
    }
}

impl<'s> Ord for KStringCow<'s> {
    #[inline]
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.as_str().cmp(other.as_str())
    }
}

impl<'s> PartialOrd for KStringCow<'s> {
    #[inline]
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        self.as_str().partial_cmp(other.as_str())
    }
}

impl<'s> std::hash::Hash for KStringCow<'s> {
    #[inline]
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.as_str().hash(state);
    }
}

impl<'s> fmt::Display for KStringCow<'s> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self.as_str(), f)
    }
}

impl<'s> AsRef<str> for KStringCow<'s> {
    #[inline]
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl<'s> AsRef<[u8]> for KStringCow<'s> {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl<'s> AsRef<std::ffi::OsStr> for KStringCow<'s> {
    #[inline]
    fn as_ref(&self) -> &std::ffi::OsStr {
        (&**self).as_ref()
    }
}

impl<'s> AsRef<std::path::Path> for KStringCow<'s> {
    #[inline]
    fn as_ref(&self) -> &std::path::Path {
        std::path::Path::new(self)
    }
}

impl<'s> std::borrow::Borrow<str> for KStringCow<'s> {
    #[inline]
    fn borrow(&self) -> &str {
        self.as_str()
    }
}

impl<'s> Default for KStringCow<'s> {
    #[inline]
    fn default() -> Self {
        Self::from_static("")
    }
}

impl From<KString> for KStringCow<'static> {
    #[inline]
    fn from(other: KString) -> Self {
        let inner = KStringCowInner::Owned(other);
        Self { inner }
    }
}

impl<'s> From<&'s KString> for KStringCow<'s> {
    #[inline]
    fn from(other: &'s KString) -> Self {
        let other = other.as_ref();
        other.into()
    }
}

impl<'s> From<KStringRef<'s>> for KStringCow<'s> {
    #[inline]
    fn from(other: KStringRef<'s>) -> Self {
        match other.inner {
            KStringRefInner::Borrowed(s) => Self::from_ref(s),
            KStringRefInner::Singleton(s) => Self::from_static(s),
        }
    }
}

impl<'s> From<&'s KStringRef<'s>> for KStringCow<'s> {
    #[inline]
    fn from(other: &'s KStringRef<'s>) -> Self {
        match other.inner {
            KStringRefInner::Borrowed(s) => Self::from_ref(s),
            KStringRefInner::Singleton(s) => Self::from_static(s),
        }
    }
}

impl From<StdString> for KStringCow<'static> {
    #[inline]
    fn from(other: StdString) -> Self {
        // Since the memory is already allocated, don't bother moving it into a FixedString
        Self::from_boxed(other.into_boxed_str())
    }
}

impl<'s> From<&'s StdString> for KStringCow<'s> {
    #[inline]
    fn from(other: &'s StdString) -> Self {
        Self::from_ref(other.as_str())
    }
}

impl From<BoxedStr> for KStringCow<'static> {
    #[inline]
    fn from(other: BoxedStr) -> Self {
        // Since the memory is already allocated, don't bother moving it into a FixedString
        Self::from_boxed(other)
    }
}

impl<'s> From<&'s BoxedStr> for KStringCow<'s> {
    #[inline]
    fn from(other: &'s BoxedStr) -> Self {
        Self::from_ref(other)
    }
}

impl<'s> From<&'s str> for KStringCow<'s> {
    #[inline]
    fn from(other: &'s str) -> Self {
        Self::from_ref(other)
    }
}

impl<'s> serde::Serialize for KStringCow<'s> {
    #[inline]
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        serializer.serialize_str(self.as_str())
    }
}

impl<'de, 's> serde::Deserialize<'de> for KStringCow<'s> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        use std::borrow::Cow;
        let s: Cow<'_, str> = Cow::deserialize(deserializer)?;
        let s = match s {
            Cow::Owned(s) => KStringCow::from_boxed(s.into_boxed_str()),
            Cow::Borrowed(s) => KStringCow::from_ref(s),
        };
        Ok(s)
    }
}

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

    #[test]
    fn test_size() {
        println!(
            "Cow: {}",
            std::mem::size_of::<std::borrow::Cow<'static, str>>()
        );
        println!("KStringCow: {}", std::mem::size_of::<KStringCow<'static>>());
    }
}
<|endoftext|>


<commit_before>/* Copyright (C)  2016 nokaa <nokaa@cock.li>
 * This software is licensed under the terms of the
 * GNU Affero General Public License. You should have
 * received a copy of this license with this software.
 * The license may also be found at https://gnu.org/licenses/agpl.txt
 */

mod command;
mod cursor;
mod insert;
mod normal;

use rustty::{self, Event, Color};
use editor;

/// `Term` represents our client application. This allows
/// us to work with the filesystem and the UI.
pub struct Term<'a> {
    /// Represents the location of the cursor in our UI
    cursor: cursor::Cursor,
    /// Contains file information; allows us to work with
    /// the filesystem
    editor: &'a mut editor::Editor<'a>,
    /// This is the UI itself
    term: rustty::Terminal,
    /// Represents the running status
    quit: bool,
    /// Represents the topmost line of the file we are editing in our UI
    line: usize,
    /// Represents the total number of lines in the currently
    /// open file
    total_lines: usize,
    partial_lines: Vec<usize>,
}

impl<'a> Term<'a> {
    /// Creates a new `Term` using the given `editor`.
    pub fn new(editor: &'a mut editor::Editor<'a>) -> Term<'a> {
        Term {
            cursor: cursor::Cursor::new(Color::Red),
            editor: editor,
            term: rustty::Terminal::new().unwrap(),
            quit: false,
            line: 0,
            total_lines: 0,
            partial_lines: vec![],
        }
    }

    /// Launches the terminal.
    pub fn run(&mut self) {
        self.editor.read_file();
        let lines = self.editor.contents.len() as isize;
        self.set_total_lines(lines);

        self.term[self.cursor.current_pos()].set_bg(self.cursor.color);
        let current_line = self.current_line();
        self.print_file(current_line);
        self.prompt();
        self.term.swap_buffers().unwrap();

        while !self.quit {
            let evt = self.term.get_event(100).unwrap();
            if let Some(Event::Key(ch)) = evt {
                if self.editor.normal_mode() {
                    normal::handle(self, ch);
                } else if self.editor.command_mode() {
                    command::handle(self, ch);
                } else {
                    insert::handle(self, ch);
                }

                if self.cursor.pos.x > self.term.cols() - 1 {
                    self.term[self.cursor.last_pos()].set_bg(Color::Default);
                    self.cursor.save_pos();
                    self.cursor.pos.x = 0;
                    self.cursor.pos.y += 1;
                }
                if self.cursor.pos.y >= self.term.rows() - 1 {
                    self.term[self.cursor.last_pos()].set_bg(Color::Default);
                    self.cursor.save_pos();
                    self.cursor.pos.x = 0;
                    self.cursor.pos.y = 0;
                }

                self.term[self.cursor.last_pos()].set_bg(Color::Default);
                self.term[self.cursor.current_pos()].set_bg(self.cursor.color);
                self.term.swap_buffers().unwrap();
            }
        }
    }

    /// Prints our prompt to the UI.
    pub fn prompt(&mut self) {
        let w = self.term.cols();
        let h = self.term.rows();

        for i in 0..w {
            self.term[(i, h - 2)].set_bg(Color::Red);
        }

        for (i, c) in self.editor.filename().chars().enumerate() {
            self.term[(i, h - 2)].set_ch(c);
        }
    }

    /// Prints our editor's contents to the UI.
    fn print_file(&mut self, start: usize) {
        self.partial_lines = vec![];
        let w = self.term.cols();
        let mut i = 0;
        let mut j = 0;
        for line in &self.editor.contents {
            if i < start {
                i += 1;
                continue;
            }

            for &b in line {
                if b == b'\n' {
                    continue;
                } else if j == w {
                    i += 1;
                    j = 0;
                    self.partial_lines.push(i - start);
                }

                self.term[(j, i - start)].set_ch(b as char);
                j += 1;
            }
            while j < w {
                self.term[(j, i - start)].set_ch(' ');
                j += 1;
            }

            i += 1;
            j = 0;
            if i - start == self.term.rows() - 2 {
                break;
            }
        }
    }

    /// Handles moving the cursor
    pub fn move_cursor(&mut self, direction: cursor::Direction) {
        match direction {
            cursor::Direction::Up => {
                if self.cursor.pos.y > 0 {
                    self.cursor.save_pos();
                    let mut i = self.cursor.pos.y - 1;
                    while self.partial_lines.contains(&i) {
                        self.cursor.pos.y -= 1;
                        i -= 1;
                    }
                    self.cursor.pos.y -= 1;
                    let curr = self.current_line() - 1;
                    self.set_current_line(curr);

                    let len = self.editor.contents[curr].len() - 1;
                    if len == 0 && self.cursor.pos.x > len {
                        self.cursor.pos.x = len;
                        self.cursor.in_line = len;
                    } else if len > 0 && self.cursor.pos.x > len - 1 {
                        self.cursor.pos.x = len - 1;
                        self.cursor.in_line = len - 1;
                    }
                }
            }
            cursor::Direction::Down => {
                if self.cursor.pos.y < self.term.rows() - 3 &&
                   self.cursor.pos.y < self.editor.contents.len() - 1
                {
                    let curr = self.current_line();
                    let len = self.editor.contents[curr].len() - 1;

                    self.cursor.save_pos();
                    self.set_current_line(curr + 1);

                    if len > self.term.cols() {
                        let mut adv = len / self.term.cols();
                        if len % self.term.cols() > 0 {
                            adv += 1;
                        }
                        if self.partial_lines.contains(&self.cursor.pos.y) {
                            adv -= 1;
                        }
                        self.cursor.pos.y += adv;
                    } else {
                        self.cursor.pos.y += 1;
                    }

                    let curr = self.current_line();
                    let len = self.editor.contents[curr].len() - 1;
                    if len == 0 && self.cursor.pos.x > len {
                        self.cursor.pos.x = len;
                        self.cursor.in_line = len;
                    } else if len > 0 && self.cursor.pos.x > len - 1 {
                        self.cursor.pos.x = len - 1;
                        self.cursor.in_line = len - 1;
                    }
                }
            }
            cursor::Direction::Left => {
                let y = self.cursor.pos.y;

                if self.cursor.pos.x != 0 {
                    self.cursor.save_pos();
                    self.cursor.pos.x -= 1;
                    self.cursor.in_line -= 1;
                } else if self.partial_lines.contains(&y) {
                    self.cursor.save_pos();
                    self.cursor.pos.y -= 1;
                    self.cursor.pos.x = self.term.cols() - 1;
                    self.cursor.in_line -= 1;
                }
            }
            cursor::Direction::Right => {
                let x = self.cursor.pos.x;
                let curr = self.current_line();
                let len = self.editor.contents[curr].len() - 1;

                if len > 0 && self.cursor.in_line < len - 1 {
                    if x < self.term.cols() - 1 {
                        self.cursor.save_pos();
                        self.cursor.pos.x += 1;
                        self.cursor.in_line += 1;
                    } else {
                        self.cursor.save_pos();
                        self.cursor.pos.x = 0;
                        self.cursor.pos.y += 1;
                        self.cursor.in_line += 1;
                    }
                }
            }
        }
    }

    /// Changes the value of the `quit` attribute to `true`.
    pub fn quit(&mut self) {
        self.quit = true;
    }

    /// Returns the total lines in our file
    pub fn total_lines(&self) -> usize {
        self.total_lines
    }

    /// Allows us to modify the total number of lines
    /// in our file, e.g. if a new line is added.
    pub fn set_total_lines(&mut self, change: isize) {
        let new = self.total_lines as isize + change;
        self.total_lines = new as usize;
    }

    /// Gives the current line at the top of our UI
    pub fn current_line(&self) -> usize {
        self.line
    }

    /// Allows us to change what the topmost line in the UI is
    pub fn set_current_line(&mut self, line: usize) {
        self.line = line;
    }

    /// This function redraws the portion of our UI displaying
    /// file contents. E.g. this is called when the current line
    /// changes.
    pub fn redraw_file(&mut self) {
        let current_line = self.current_line();
        self.print_file(current_line);
    }

    /// This function redraws the given line of the UI on the screen.
    pub fn redraw_line(&mut self, ui_line: usize) {
        let file_line = ui_line + self.current_line();
        self.print_line(ui_line, file_line);
    }

    pub fn print_line(&mut self, ui_line: usize, file_line: usize) {
        let contents = &self.editor.contents[file_line];
        let w = self.term.cols();
        let mut i = 0;
        let mut j = 0;

        for &b in contents {
            if b == b'\n' {
                continue;
            } else if i == w {
                i = 0;
                j += 1;
            }
            self.term[(i, ui_line + j)].set_ch(b as char);
            i += 1;
        }

        while i < self.term.cols() {
            self.term[(i, ui_line + j)].set_ch(' ');
            i += 1;
        }
    }
}
<commit_msg>Fix several bugs with up movement.<commit_after>/* Copyright (C)  2016 nokaa <nokaa@cock.li>
 * This software is licensed under the terms of the
 * GNU Affero General Public License. You should have
 * received a copy of this license with this software.
 * The license may also be found at https://gnu.org/licenses/agpl.txt
 */

mod command;
mod cursor;
mod insert;
mod normal;

use rustty::{self, Event, Color};
use editor;

/// `Term` represents our client application. This allows
/// us to work with the filesystem and the UI.
pub struct Term<'a> {
    /// Represents the location of the cursor in our UI
    cursor: cursor::Cursor,
    /// Contains file information; allows us to work with
    /// the filesystem
    editor: &'a mut editor::Editor<'a>,
    /// This is the UI itself
    term: rustty::Terminal,
    /// Represents the running status
    quit: bool,
    /// Represents the topmost line of the file we are editing in our UI
    line: usize,
    /// Represents the total number of lines in the currently
    /// open file
    total_lines: usize,
    partial_lines: Vec<usize>,
}

impl<'a> Term<'a> {
    /// Creates a new `Term` using the given `editor`.
    pub fn new(editor: &'a mut editor::Editor<'a>) -> Term<'a> {
        Term {
            cursor: cursor::Cursor::new(Color::Red),
            editor: editor,
            term: rustty::Terminal::new().unwrap(),
            quit: false,
            line: 0,
            total_lines: 0,
            partial_lines: vec![],
        }
    }

    /// Launches the terminal.
    pub fn run(&mut self) {
        self.editor.read_file();
        let lines = self.editor.contents.len() as isize;
        self.set_total_lines(lines);

        self.term[self.cursor.current_pos()].set_bg(self.cursor.color);
        let current_line = self.current_line();
        self.print_file(current_line);
        self.prompt();
        self.term.swap_buffers().unwrap();

        while !self.quit {
            let evt = self.term.get_event(100).unwrap();
            if let Some(Event::Key(ch)) = evt {
                if self.editor.normal_mode() {
                    normal::handle(self, ch);
                } else if self.editor.command_mode() {
                    command::handle(self, ch);
                } else {
                    insert::handle(self, ch);
                }

                if self.cursor.pos.x > self.term.cols() - 1 {
                    self.term[self.cursor.last_pos()].set_bg(Color::Default);
                    self.cursor.save_pos();
                    self.cursor.pos.x = 0;
                    self.cursor.pos.y += 1;
                }
                if self.cursor.pos.y >= self.term.rows() - 1 {
                    self.term[self.cursor.last_pos()].set_bg(Color::Default);
                    self.cursor.save_pos();
                    self.cursor.pos.x = 0;
                    self.cursor.pos.y = 0;
                }

                self.term[self.cursor.last_pos()].set_bg(Color::Default);
                self.term[self.cursor.current_pos()].set_bg(self.cursor.color);
                self.term.swap_buffers().unwrap();
            }
        }
    }

    /// Prints our prompt to the UI.
    pub fn prompt(&mut self) {
        let w = self.term.cols();
        let h = self.term.rows();

        for i in 0..w {
            self.term[(i, h - 2)].set_bg(Color::Red);
        }

        for (i, c) in self.editor.filename().chars().enumerate() {
            self.term[(i, h - 2)].set_ch(c);
        }
    }

    /// Prints our editor's contents to the UI.
    fn print_file(&mut self, start: usize) {
        self.partial_lines = vec![];
        let w = self.term.cols();
        let mut i = 0;
        let mut j = 0;
        for line in &self.editor.contents {
            if i < start {
                i += 1;
                continue;
            }

            for &b in line {
                if b == b'\n' {
                    continue;
                } else if j == w {
                    i += 1;
                    j = 0;
                    self.partial_lines.push(i - start);
                }

                self.term[(j, i - start)].set_ch(b as char);
                j += 1;
            }
            while j < w {
                self.term[(j, i - start)].set_ch(' ');
                j += 1;
            }

            i += 1;
            j = 0;
            if i - start == self.term.rows() - 2 {
                break;
            }
        }
    }

    /// Handles moving the cursor
    pub fn move_cursor(&mut self, direction: cursor::Direction) {
        match direction {
            cursor::Direction::Up => {
                if self.cursor.pos.y > 0 {
                    self.cursor.save_pos();
                    let mut i = self.cursor.pos.y;// - 1;
                    if self.partial_lines.contains(&i) {
                        self.cursor.pos.y -= 1;
                    }
                    i -= 1;

                    while self.partial_lines.contains(&i) {
                        self.cursor.pos.y -= 1;
                        i -= 1;
                    }
                    self.cursor.pos.y -= 1;
                    let curr = self.current_line() - 1;
                    self.set_current_line(curr);

                    let len = self.editor.contents[curr].len() - 1;
                    if len == 0 && self.cursor.pos.x > len {
                        self.cursor.pos.x = len;
                        self.cursor.in_line = len;
                    } else if len > 0 && self.cursor.pos.x > len - 1 {
                        self.cursor.pos.x = len - 1;
                        self.cursor.in_line = len - 1;
                    }
                }
            }
            cursor::Direction::Down => {
                if self.cursor.pos.y < self.term.rows() - 3 &&
                   self.cursor.pos.y < self.editor.contents.len() - 1
                {
                    let curr = self.current_line();
                    let len = self.editor.contents[curr].len() - 1;

                    self.cursor.save_pos();
                    self.set_current_line(curr + 1);

                    if len > self.term.cols() {
                        let mut adv = len / self.term.cols();
                        if len % self.term.cols() > 0 {
                            adv += 1;
                        }
                        if self.partial_lines.contains(&self.cursor.pos.y) {
                            adv -= 1;
                        }
                        self.cursor.pos.y += adv;
                    } else {
                        self.cursor.pos.y += 1;
                    }

                    let curr = self.current_line();
                    let len = self.editor.contents[curr].len() - 1;
                    if len == 0 && self.cursor.pos.x > len {
                        self.cursor.pos.x = len;
                        self.cursor.in_line = len;
                    } else if len > 0 && self.cursor.pos.x > len - 1 {
                        self.cursor.pos.x = len - 1;
                        self.cursor.in_line = len - 1;
                    }
                }
            }
            cursor::Direction::Left => {
                let y = self.cursor.pos.y;

                if self.cursor.pos.x != 0 {
                    self.cursor.save_pos();
                    self.cursor.pos.x -= 1;
                    self.cursor.in_line -= 1;
                } else if self.partial_lines.contains(&y) {
                    self.cursor.save_pos();
                    self.cursor.pos.y -= 1;
                    self.cursor.pos.x = self.term.cols() - 1;
                    self.cursor.in_line -= 1;
                }
            }
            cursor::Direction::Right => {
                let x = self.cursor.pos.x;
                let curr = self.current_line();
                let len = self.editor.contents[curr].len() - 1;

                if len > 0 && self.cursor.in_line < len - 1 {
                    if x < self.term.cols() - 1 {
                        self.cursor.save_pos();
                        self.cursor.pos.x += 1;
                        self.cursor.in_line += 1;
                    } else {
                        self.cursor.save_pos();
                        self.cursor.pos.x = 0;
                        self.cursor.pos.y += 1;
                        self.cursor.in_line += 1;
                    }
                }
            }
        }
    }

    /// Changes the value of the `quit` attribute to `true`.
    pub fn quit(&mut self) {
        self.quit = true;
    }

    /// Returns the total lines in our file
    pub fn total_lines(&self) -> usize {
        self.total_lines
    }

    /// Allows us to modify the total number of lines
    /// in our file, e.g. if a new line is added.
    pub fn set_total_lines(&mut self, change: isize) {
        let new = self.total_lines as isize + change;
        self.total_lines = new as usize;
    }

    /// Gives the current line at the top of our UI
    pub fn current_line(&self) -> usize {
        self.line
    }

    /// Allows us to change what the topmost line in the UI is
    pub fn set_current_line(&mut self, line: usize) {
        self.line = line;
    }

    /// This function redraws the portion of our UI displaying
    /// file contents. E.g. this is called when the current line
    /// changes.
    pub fn redraw_file(&mut self) {
        let current_line = self.current_line();
        self.print_file(current_line);
    }

    /// This function redraws the given line of the UI on the screen.
    pub fn redraw_line(&mut self, ui_line: usize) {
        let file_line = ui_line + self.current_line();
        self.print_line(ui_line, file_line);
    }

    pub fn print_line(&mut self, ui_line: usize, file_line: usize) {
        let contents = &self.editor.contents[file_line];
        let w = self.term.cols();
        let mut i = 0;
        let mut j = 0;

        for &b in contents {
            if b == b'\n' {
                continue;
            } else if i == w {
                i = 0;
                j += 1;
            }
            self.term[(i, ui_line + j)].set_ch(b as char);
            i += 1;
        }

        while i < self.term.cols() {
            self.term[(i, ui_line + j)].set_ch(' ');
            i += 1;
        }
    }
}
<|endoftext|>


<commit_before>#![feature(unsize, coerce_unsized)]

fn test_basic() {
    #[repr(packed)]
    struct S {
        a: i32,
        b: i64,
    }

    #[repr(packed)]
    #[allow(dead_code)]
    struct Test1<'a> {
        x: u8,
        other: &'a u32,
    }

    #[repr(packed)]
    #[allow(dead_code)]
    struct Test2<'a> {
        x: u8,
        other: &'a Test1<'a>,
    }

    fn test(t: Test2) {
        let x = *t.other.other;
        assert_eq!(x, 42);
    }

    let mut x = S {
        a: 42,
        b: 99,
    };
    let a = x.a;
    let b = x.b;
    assert_eq!(a, 42);
    assert_eq!(b, 99);
    // can't do `assert_eq!(x.a, 42)`, because `assert_eq!` takes a reference
    assert_eq!({x.a}, 42);
    assert_eq!({x.b}, 99);

    x.b = 77;
    assert_eq!({x.b}, 77);

    test(Test2 { x: 0, other: &Test1 { x: 0, other: &42 }});
}

fn test_unsizing() {
    #[repr(packed)]
    #[allow(dead_code)]
    struct UnalignedPtr<'a, T: ?Sized>
    where T: 'a,
    {
        data: &'a T,
    }

    impl<'a, T, U> std::ops::CoerceUnsized<UnalignedPtr<'a, U>> for UnalignedPtr<'a, T>
    where
        T: std::marker::Unsize<U> + ?Sized,
        U: ?Sized,
    { }

    let arr = [1, 2, 3];
    let arr_unaligned: UnalignedPtr<[i32; 3]> = UnalignedPtr { data: &arr };
    let arr_unaligned: UnalignedPtr<[i32]> = arr_unaligned;
    let _unused = &arr_unaligned; // forcing an allocation, which could also yield "unaligned write"-errors
}

fn test_drop() {
    struct Wrap(u32);
    impl Drop for Wrap {
        fn drop(&mut self) {
            // Do an (aligned) load
            let _test = self.0;
            // For the fun of it, test alignment
            assert_eq!(&self.0 as *const _ as usize % std::mem::align_of::<u32>(), 0);
        }
    }

    #[repr(packed,C)]
    struct Packed<T> {
        f1: u8, // this should move the second field to something not very aligned
        f2: T,
    }

    let p = Packed { f1: 42, f2: Wrap(23) };
    drop(p);
}

fn test_inner_packed() {
    // Even if just the inner struct is packed, accesses to the outer field can get unaligned.
    // Make sure that works.
    #[repr(packed)]
    #[derive(Clone,Copy)]
    struct Inner(u32);

    #[derive(Clone,Copy)]
    struct Outer(u8, Inner);

    let o = Outer(0, Inner(42));
    let _x = o.1;
    let _y = (o.1).0;
    let _o2 = o.clone();
}

fn test_static() {
    #[repr(packed)]
    struct Foo {
        i: i32
    }

    static FOO: Foo = Foo { i: 42 };

    assert_eq!({FOO.i}, 42);
}

fn main() {
    test_basic();
    test_unsizing();
    test_drop();
    test_inner_packed();
    test_static();
}
<commit_msg>Auto merge of #1343 - RalfJung:derive-packed, r=RalfJung<commit_after>#![feature(unsize, coerce_unsized)]

use std::collections::hash_map::DefaultHasher;
use std::hash::Hash;

fn test_basic() {
    #[repr(packed)]
    struct S {
        a: i32,
        b: i64,
    }

    #[repr(packed)]
    #[allow(dead_code)]
    struct Test1<'a> {
        x: u8,
        other: &'a u32,
    }

    #[repr(packed)]
    #[allow(dead_code)]
    struct Test2<'a> {
        x: u8,
        other: &'a Test1<'a>,
    }

    fn test(t: Test2) {
        let x = *t.other.other;
        assert_eq!(x, 42);
    }

    let mut x = S {
        a: 42,
        b: 99,
    };
    let a = x.a;
    let b = x.b;
    assert_eq!(a, 42);
    assert_eq!(b, 99);
    // can't do `assert_eq!(x.a, 42)`, because `assert_eq!` takes a reference
    assert_eq!({x.a}, 42);
    assert_eq!({x.b}, 99);

    x.b = 77;
    assert_eq!({x.b}, 77);

    test(Test2 { x: 0, other: &Test1 { x: 0, other: &42 }});
}

fn test_unsizing() {
    #[repr(packed)]
    #[allow(dead_code)]
    struct UnalignedPtr<'a, T: ?Sized>
    where T: 'a,
    {
        data: &'a T,
    }

    impl<'a, T, U> std::ops::CoerceUnsized<UnalignedPtr<'a, U>> for UnalignedPtr<'a, T>
    where
        T: std::marker::Unsize<U> + ?Sized,
        U: ?Sized,
    { }

    let arr = [1, 2, 3];
    let arr_unaligned: UnalignedPtr<[i32; 3]> = UnalignedPtr { data: &arr };
    let arr_unaligned: UnalignedPtr<[i32]> = arr_unaligned;
    let _unused = &arr_unaligned; // forcing an allocation, which could also yield "unaligned write"-errors
}

fn test_drop() {
    struct Wrap(u32);
    impl Drop for Wrap {
        fn drop(&mut self) {
            // Do an (aligned) load
            let _test = self.0;
            // For the fun of it, test alignment
            assert_eq!(&self.0 as *const _ as usize % std::mem::align_of::<u32>(), 0);
        }
    }

    #[repr(packed,C)]
    struct Packed<T> {
        f1: u8, // this should move the second field to something not very aligned
        f2: T,
    }

    let p = Packed { f1: 42, f2: Wrap(23) };
    drop(p);
}

fn test_inner_packed() {
    // Even if just the inner struct is packed, accesses to the outer field can get unaligned.
    // Make sure that works.
    #[repr(packed)]
    #[derive(Clone,Copy)]
    struct Inner(u32);

    #[derive(Clone,Copy)]
    struct Outer(u8, Inner);

    let o = Outer(0, Inner(42));
    let _x = o.1;
    let _y = (o.1).0;
    let _o2 = o.clone();
}

fn test_static() {
    #[repr(packed)]
    struct Foo {
        i: i32
    }

    static FOO: Foo = Foo { i: 42 };

    assert_eq!({FOO.i}, 42);
}

fn test_derive() {
    #[repr(packed)]
    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
    struct P {
        a: usize,
        b: u8,
        c: usize,
    }

    let x = P {a: 1usize, b: 2u8, c: 3usize};
    let y = P {a: 1usize, b: 2u8, c: 4usize};

    let _clone = x.clone();
    assert!(x != y);
    assert_eq!(x.partial_cmp(&y).unwrap(), x.cmp(&y));
    x.hash(&mut DefaultHasher::new());
    P::default();
    format!("{:?}", x);
}

fn main() {
    test_basic();
    test_unsizing();
    test_drop();
    test_inner_packed();
    test_static();
    test_derive();
}
<|endoftext|>


<commit_before>macro_rules! assert_special {
    ($left:expr, $right:expr) => ({
        match (&$left, &$right) {
            (left_val, right_val) => {
                if !(*left_val == *right_val) {
                    panic!("assertion_failed: `(left == right)`\
                            (left: `{:?}` right: `{:?}`)",
                    left_val, right_val)
                }

                true
            }
        }
    });
}

macro_rules! vector {
    ($elem:expr, $n:expr) => {
        ::std::vec::from_elem($elem, $n)
    };
    ($($x:expr),*) => {
        <[_]>::into_vec(Box::new([ $( $x ), *]))
    };
    // adds support for trailing comma
    ($($x:expr),+ ,) => {
        // delegate creation to second macro case
        vector![$($x), *]
    }
}

// Pattern language of regular expressions:

// $( ... )* Match 0 or more times with no separator

// $( ... ),* Match 0 or more times, separated by commas

// $( ... );* Match 0 or more times, separated by semicolons

// $( ... )+ Match 1 or more times with no separator

// $( ... ),+ Match 1 or more times, separated by commas

// $( ... );+ Match 1 or more times, separated by semicolons

fn main() {
    let val = assert_special!("hello", "hello");
    println!("{:?}", val);

    let some_vector = vector![10, 1];
    println!("{:?}", some_vector);

    // third case with trailing comma
    let some_vector_with_trailing_comma = vector![10, 1, 10,];
    println!("{:?}", some_vector_with_trailing_comma);
}
<commit_msg>wip json macro<commit_after>use std::collections::HashMap;

macro_rules! assert_special {
    ($left:expr, $right:expr) => ({
        match (&$left, &$right) {
            (left_val, right_val) => {
                if !(*left_val == *right_val) {
                    panic!("assertion_failed: `(left == right)`\
                            (left: `{:?}` right: `{:?}`)",
                    left_val, right_val)
                }

                true
            }
        }
    });
}

macro_rules! vector {
    ($elem:expr, $n:expr) => {
        ::std::vec::from_elem($elem, $n)
    };
    ($($x:expr),*) => {
        <[_]>::into_vec(Box::new([ $( $x ), *]))
    };
    // adds support for trailing comma
    ($($x:expr),+ ,) => {
        // delegate creation to second macro case
        vector![$($x), *]
    }
}

// Pattern language of regular expressions:

// $( ... )* Match 0 or more times with no separator

// $( ... ),* Match 0 or more times, separated by commas

// $( ... );* Match 0 or more times, separated by semicolons

// $( ... )+ Match 1 or more times with no separator

// $( ... ),+ Match 1 or more times, separated by commas

// $( ... );+ Match 1 or more times, separated by semicolons

#[derive(Clone, PartialEq, Debug)]
enum Json {
    Null,
    Boolean(bool),
    Number(f64),
    String(String),
    Array(Vec<Json>),
    Object(Box<HashMap<String, Json>>)
}

fn main() {
    let val = assert_special!("hello", "hello");
    println!("{:?}", val);

    let some_vector = vector![10, 1];
    println!("{:?}", some_vector);

    // third case with trailing comma
    let some_vector_with_trailing_comma = vector![10, 1, 10,];
    println!("{:?}", some_vector_with_trailing_comma);

    // initialize Json structure without a macro
    let students = Json::Array(vec![
        Json::Object(Box::new(vec![
            ("name".to_string(), Json::String("Raventid".to_string())),
            ("age".to_string(), Json::Number(32.))
        ].into_iter().collect())),
        Json::Object(Box::new(vec![
            ("name".to_string(), Json::String("Raventida".to_string())),
            ("age".to_string(), Json::Number(26.))
        ].into_iter().collect()))
    ]);

    // let's delegate this code generation to macro
    let students = json!([{
        "name": "Raventid",
        "class_of": 32
    },
    {
        "name": "Raventida",
        "age": 26
    }]);

    println!("{:?}", students);
}
<|endoftext|>


<commit_before>use openvr_sys as sys;

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TrackingUniverseOrigin {
    Seated = sys::ETrackingUniverseOrigin_TrackingUniverseSeated as isize,
    Standing = sys::ETrackingUniverseOrigin_TrackingUniverseStanding as isize,
    RawAndUncalibrated = sys::ETrackingUniverseOrigin_TrackingUniverseRawAndUncalibrated as isize,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct TrackedDevicePose(sys::TrackedDevicePose_t);

impl TrackedDevicePose {
    pub fn device_to_absolute_tracking(&self) -> &[[f32; 4]; 3] { &self.0.mDeviceToAbsoluteTracking.m }
    pub fn velocity(&self) -> &[f32; 3] { &self.0.vVelocity.v }
    pub fn angular_velocity(&self) -> &[f32; 3] { &self.0.vAngularVelocity.v }
    pub fn tracking_result(&self) -> TrackingResult {
        use self::TrackingResult::*;
        match self.0.eTrackingResult {
            sys::ETrackingResult_TrackingResult_Uninitialized => Uninitialized,
            sys::ETrackingResult_TrackingResult_Calibrating_InProgress => CalibratingInProgress,
            sys::ETrackingResult_TrackingResult_Calibrating_OutOfRange => CalibratingOutOfRange,
            sys::ETrackingResult_TrackingResult_Running_OK => OK,
            sys::ETrackingResult_TrackingResult_Running_OutOfRange => RunningOutOfRange,
            _ => panic!("unrecognized tracking result")
        }
    }
    pub fn pose_is_valid(&self) -> bool { self.0.bPoseIsValid }
    pub fn device_is_connected(&self) -> bool { self.0.bDeviceIsConnected }
}

#[derive(Debug, Copy, Clone)]
pub enum TrackingResult {
    Uninitialized = sys::ETrackingResult_TrackingResult_Uninitialized as isize,
    CalibratingInProgress = sys::ETrackingResult_TrackingResult_Calibrating_InProgress as isize,
    CalibratingOutOfRange = sys::ETrackingResult_TrackingResult_Calibrating_OutOfRange as isize,
    OK = sys::ETrackingResult_TrackingResult_Running_OK as isize,
    RunningOutOfRange = sys::ETrackingResult_TrackingResult_Running_OutOfRange as isize,
}

#[derive(Debug, Copy, Clone)]
pub enum TrackedDeviceClass {
    Invalid = sys::ETrackedDeviceClass_TrackedDeviceClass_Invalid as isize,
    HMD = sys::ETrackedDeviceClass_TrackedDeviceClass_HMD as isize,
    Controller = sys::ETrackedDeviceClass_TrackedDeviceClass_Controller as isize,
    GenericTracker = sys::ETrackedDeviceClass_TrackedDeviceClass_GenericTracker as isize,
    TrackingReference = sys::ETrackedDeviceClass_TrackedDeviceClass_TrackingReference as isize,
    DisplayRedirect = sys::ETrackedDeviceClass_TrackedDeviceClass_DisplayRedirect as isize,
}

pub type TrackedDeviceIndex = sys::TrackedDeviceIndex_t;

pub mod tracked_device_index {
    use super::*;
    pub const HMD: TrackedDeviceIndex = sys::k_unTrackedDeviceIndex_Hmd;
    pub const INVALID: TrackedDeviceIndex = sys::k_unTrackedDeviceIndexInvalid;
}

pub type TrackedDeviceProperty = sys::ETrackedDeviceProperty;

#[derive(Debug, Copy, Clone)]
pub enum TrackedControllerRole {
    LeftHand = sys::ETrackedControllerRole_TrackedControllerRole_LeftHand as isize,
    RightHand = sys::ETrackedControllerRole_TrackedControllerRole_RightHand as isize,
}

pub const MAX_TRACKED_DEVICE_COUNT: usize = sys::k_unMaxTrackedDeviceCount as usize;

pub type TrackedDevicePoses = [TrackedDevicePose; MAX_TRACKED_DEVICE_COUNT];
<commit_msg>Add some missing derives<commit_after>use openvr_sys as sys;

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TrackingUniverseOrigin {
    Seated = sys::ETrackingUniverseOrigin_TrackingUniverseSeated as isize,
    Standing = sys::ETrackingUniverseOrigin_TrackingUniverseStanding as isize,
    RawAndUncalibrated = sys::ETrackingUniverseOrigin_TrackingUniverseRawAndUncalibrated as isize,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct TrackedDevicePose(sys::TrackedDevicePose_t);

impl TrackedDevicePose {
    pub fn device_to_absolute_tracking(&self) -> &[[f32; 4]; 3] { &self.0.mDeviceToAbsoluteTracking.m }
    pub fn velocity(&self) -> &[f32; 3] { &self.0.vVelocity.v }
    pub fn angular_velocity(&self) -> &[f32; 3] { &self.0.vAngularVelocity.v }
    pub fn tracking_result(&self) -> TrackingResult {
        use self::TrackingResult::*;
        match self.0.eTrackingResult {
            sys::ETrackingResult_TrackingResult_Uninitialized => Uninitialized,
            sys::ETrackingResult_TrackingResult_Calibrating_InProgress => CalibratingInProgress,
            sys::ETrackingResult_TrackingResult_Calibrating_OutOfRange => CalibratingOutOfRange,
            sys::ETrackingResult_TrackingResult_Running_OK => OK,
            sys::ETrackingResult_TrackingResult_Running_OutOfRange => RunningOutOfRange,
            _ => panic!("unrecognized tracking result")
        }
    }
    pub fn pose_is_valid(&self) -> bool { self.0.bPoseIsValid }
    pub fn device_is_connected(&self) -> bool { self.0.bDeviceIsConnected }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TrackingResult {
    Uninitialized = sys::ETrackingResult_TrackingResult_Uninitialized as isize,
    CalibratingInProgress = sys::ETrackingResult_TrackingResult_Calibrating_InProgress as isize,
    CalibratingOutOfRange = sys::ETrackingResult_TrackingResult_Calibrating_OutOfRange as isize,
    OK = sys::ETrackingResult_TrackingResult_Running_OK as isize,
    RunningOutOfRange = sys::ETrackingResult_TrackingResult_Running_OutOfRange as isize,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TrackedDeviceClass {
    Invalid = sys::ETrackedDeviceClass_TrackedDeviceClass_Invalid as isize,
    HMD = sys::ETrackedDeviceClass_TrackedDeviceClass_HMD as isize,
    Controller = sys::ETrackedDeviceClass_TrackedDeviceClass_Controller as isize,
    GenericTracker = sys::ETrackedDeviceClass_TrackedDeviceClass_GenericTracker as isize,
    TrackingReference = sys::ETrackedDeviceClass_TrackedDeviceClass_TrackingReference as isize,
    DisplayRedirect = sys::ETrackedDeviceClass_TrackedDeviceClass_DisplayRedirect as isize,
}

pub type TrackedDeviceIndex = sys::TrackedDeviceIndex_t;

pub mod tracked_device_index {
    use super::*;
    pub const HMD: TrackedDeviceIndex = sys::k_unTrackedDeviceIndex_Hmd;
    pub const INVALID: TrackedDeviceIndex = sys::k_unTrackedDeviceIndexInvalid;
}

pub type TrackedDeviceProperty = sys::ETrackedDeviceProperty;

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TrackedControllerRole {
    LeftHand = sys::ETrackedControllerRole_TrackedControllerRole_LeftHand as isize,
    RightHand = sys::ETrackedControllerRole_TrackedControllerRole_RightHand as isize,
}

pub const MAX_TRACKED_DEVICE_COUNT: usize = sys::k_unMaxTrackedDeviceCount as usize;

pub type TrackedDevicePoses = [TrackedDevicePose; MAX_TRACKED_DEVICE_COUNT];
<|endoftext|>


<commit_before>use addressable::Addressable;
use addressable::AddressableUtil;
use ram::Ram;

enum Operand {
	Implied,							// OPC				// operand implied
	Immediate(u8),						// OPC #$BB			// operand is byte (BB)
	Accumulator,						// OPC A			// operand is AC
	Relative(i8),						// OPC $BB			// branch target is PC + offset (BB), bit 7 signifies negative offset
	Absolute(u16),						// OPC $HHLL		// operand is address $HHLL
	AbsoluteIndexedWithX(u16),			// OPC $HHLL,X		// operand is address $HHLL incremented by X with carry
	AbsoluteIndexedWithY(u16),			// OPC $HHLL,Y		// operand is address $HHLL incremented by Y with carry
	Indirect(u16),						// OPC ($HHLL)		// operand is effective address; effective address is value of address
	ZeroPage(u8),						// OPC $LL			// operand is address $00LL
	ZeroPageIndexedWithX(u8),			// OPC $LL,X		// operand is address $00LL incremented by X, no page transition
	ZeroPageIndexedWithY(u8),			// OPC $LL,Y		// operand is address $00LL incremented by Y, no page transition
	ZeroPageIndexedWithXIndirect(u8),	// OPC ($LL,X)		// operand is effective address; effective address is $00LL incremented by X without carry
	ZeroPageIndirectIndexedWithY(u8),	// OPC ($LL),Y		// operand is effective address incremented by Y with carry; effective address is word at $00LL
}

impl Operand {
	fn addr (&self, cpu: &CPU) -> u16 {
		match * self {
			Implied								=> fail!("mos6510: Implied operand is never targetted to an address"),
			Immediate(_)						=> fail!("mos6510: Immediade operand is never targetted to an address"),
			Accumulator							=> fail!("mos6510: Accumulator operand is never targetted to an address"),
			Relative(offset)					=> cpu.pc + offset as u16,
			Absolute(addr)						=> addr,
			AbsoluteIndexedWithX(addr)			=> addr + cpu.x as u16,
			AbsoluteIndexedWithY(addr)			=> addr + cpu.y as u16,
			Indirect(addr)						=> cpu.get_le(addr),
			ZeroPage(addr)						=> addr as u16,
			ZeroPageIndexedWithX(addr)			=> (addr + cpu.x) as u16,				// no page transition
			ZeroPageIndexedWithY(addr)			=> (addr + cpu.y) as u16,				// no page transition
			ZeroPageIndexedWithXIndirect(addr)	=> cpu.get_le((addr + cpu.x) as u16),	// no page transition
			ZeroPageIndirectIndexedWithY(addr)	=> { let iaddr: u16 = cpu.get_le(addr as u16); iaddr + cpu.y as u16 },
		}
	}

	fn get (&self, cpu: &CPU) -> u8 {
		match *self {
			Implied								=> fail!("mos6510: Implied operand never has a value"),
			Immediate(val)						=> val,
			Accumulator							=> cpu.ac,
			Relative(_target)					=> fail!("mos6510: Relative operand never has a value"),
			op									=> { let addr = op.addr(cpu); cpu.get(addr) },
		}
	}

	fn set (&self, val: u8, cpu: &mut CPU) {
		match *self {
			Implied								=> fail!("mos6510: Implied operand never sets a value"),
			Immediate(_)						=> fail!("mos6510: Immediate operand never sets a value"),
			Accumulator							=> cpu.ac = val,
			Relative(_target)					=> fail!("mos6510: Relative operand never sets a value"),
			op									=> { let addr = op.addr(cpu); cpu.set(addr, val); },
		}
	}
}

static NMI_VECTOR: u16 = 0xfffa;
static RESET_VECTOR: u16 = 0xfffc;
static IRQ_VECTOR: u16 = 0xfffe;

pub struct CPU {
	pc: u16,				// program counter
	ac: u8,					// accumulator
	x: u8,					// x register
	y: u8,					// y register
	sr: u8,					// status register (NV-BDIZC: Negative, oVerflow, Break, Decimal, Interrupt, Zero, Carry)
	sp: u8,					// stack pointer
	mem: Ram<u16>,
}

impl CPU {
	pub fn new () -> CPU {
		CPU { pc: 0, ac: 0, x: 0, y: 0, sr: 0, sp: 0, mem: Ram::new() }
	}
}

impl Addressable<u16> for CPU {
	pub fn get (&self, addr: u16) -> u8 {
		// TODO: addresses $0000 (data direction) and $0001 (data) are hardwired for the processor I/O port
		self.mem.get(addr)
	}

	pub fn set (&mut self, addr: u16, data: u8) {
		// TODO: addresses $0000 (data direction) and $0001 (data) are hardwired for the processor I/O port
		self.mem.set(addr, data);
	}
}
<commit_msg>Refactored CPU registers<commit_after>use addressable::Addressable;
use addressable::AddressableUtil;
use ram::Ram;

static NMI_VECTOR: u16 = 0xfffa;
static RESET_VECTOR: u16 = 0xfffc;
static IRQ_VECTOR: u16 = 0xfffe;

struct Registers {
	pc: u16,				// program counter
	ac: u8,					// accumulator
	x: u8,					// x register
	y: u8,					// y register
	sr: u8,					// status register (NV-BDIZC: Negative, oVerflow, Break, Decimal, Interrupt, Zero, Carry)
	sp: u8,					// stack pointer
}

enum Operand {
	Implied,							// OPC				// operand implied
	Immediate(u8),						// OPC #$BB			// operand is byte (BB)
	Accumulator,						// OPC A			// operand is AC
	Relative(i8),						// OPC $BB			// branch target is PC + offset (BB), bit 7 signifies negative offset
	Absolute(u16),						// OPC $HHLL		// operand is address $HHLL
	AbsoluteIndexedWithX(u16),			// OPC $HHLL,X		// operand is address $HHLL incremented by X with carry
	AbsoluteIndexedWithY(u16),			// OPC $HHLL,Y		// operand is address $HHLL incremented by Y with carry
	Indirect(u16),						// OPC ($HHLL)		// operand is effective address; effective address is value of address
	ZeroPage(u8),						// OPC $LL			// operand is address $00LL
	ZeroPageIndexedWithX(u8),			// OPC $LL,X		// operand is address $00LL incremented by X, no page transition
	ZeroPageIndexedWithY(u8),			// OPC $LL,Y		// operand is address $00LL incremented by Y, no page transition
	ZeroPageIndexedWithXIndirect(u8),	// OPC ($LL,X)		// operand is effective address; effective address is $00LL incremented by X without carry
	ZeroPageIndirectIndexedWithY(u8),	// OPC ($LL),Y		// operand is effective address incremented by Y with carry; effective address is word at $00LL
}

impl Operand {
	fn addr (&self, cpu: &Cpu) -> u16 {
		match * self {
			Implied								=> fail!("mos6510: Implied operand is never targetted to an address"),
			Immediate(_)						=> fail!("mos6510: Immediade operand is never targetted to an address"),
			Accumulator							=> fail!("mos6510: Accumulator operand is never targetted to an address"),
			Relative(offset)					=> cpu.reg.pc + offset as u16,
			Absolute(addr)						=> addr,
			AbsoluteIndexedWithX(addr)			=> addr + cpu.reg.x as u16,
			AbsoluteIndexedWithY(addr)			=> addr + cpu.reg.y as u16,
			Indirect(addr)						=> cpu.get_le(addr),
			ZeroPage(addr)						=> addr as u16,
			ZeroPageIndexedWithX(addr)			=> (addr + cpu.reg.x) as u16,				// no page transition
			ZeroPageIndexedWithY(addr)			=> (addr + cpu.reg.y) as u16,				// no page transition
			ZeroPageIndexedWithXIndirect(addr)	=> cpu.get_le((addr + cpu.reg.x) as u16),	// no page transition
			ZeroPageIndirectIndexedWithY(addr)	=> { let iaddr: u16 = cpu.get_le(addr as u16); iaddr + cpu.reg.y as u16 },
		}
	}

	fn get (&self, cpu: &Cpu) -> u8 {
		match *self {
			Implied								=> fail!("mos6510: Implied operand never has a value"),
			Immediate(val)						=> val,
			Accumulator							=> cpu.reg.ac,
			Relative(_target)					=> fail!("mos6510: Relative operand never has a value"),
			op									=> { let addr = op.addr(cpu); cpu.get(addr) },
		}
	}

	fn set (&self, cpu: &mut Cpu, val: u8) {
		match *self {
			Implied								=> fail!("mos6510: Implied operand never sets a value"),
			Immediate(_)						=> fail!("mos6510: Immediate operand never sets a value"),
			Accumulator							=> cpu.reg.ac = val,
			Relative(_target)					=> fail!("mos6510: Relative operand never sets a value"),
			op									=> { let addr = op.addr(cpu); cpu.set(addr, val); },
		}
	}
}

pub struct Cpu {
	priv reg: Registers,
	priv mem: Ram<u16>,
}

impl Cpu {
	pub fn new () -> Cpu {
		Cpu {
			reg: Registers { pc: 0, ac: 0, x: 0, y: 0, sr: 0, sp: 0 },
			mem: Ram::new()
		}
	}
}

impl Addressable<u16> for Cpu {
	pub fn get (&self, addr: u16) -> u8 {
		// TODO: addresses $0000 (data direction) and $0001 (data) are hardwired for the processor I/O port
		self.mem.get(addr)
	}

	pub fn set (&mut self, addr: u16, data: u8) {
		// TODO: addresses $0000 (data direction) and $0001 (data) are hardwired for the processor I/O port
		self.mem.set(addr, data);
	}
}
<|endoftext|>


<commit_before>#![crate_id(name="seq", vers="1.0.0", author="Daniel MacDougall")]

#![feature(macro_rules)]

// TODO: Make -w flag work with decimals
// TODO: Support -f flag

extern crate getopts;
extern crate libc;

use std::os;

#[path = "../common/util.rs"]
mod util;

static NAME: &'static str = "seq";

#[deriving(Clone)]
struct SeqOptions {
    separator: String,
    terminator: Option<String>,
    widths: bool
}

fn parse_float(s: &str) -> Result<f64, String>{
    match from_str(s) {
        Some(n) => Ok(n),
        None => Err(format!("seq: invalid floating point argument: {:s}", s))
    }
}

fn escape_sequences(s: &str) -> String {
    s.replace("\\n", "\n").
        replace("\\t", "\t")
}

fn parse_options(args: Vec<String>, options: &mut SeqOptions) -> Result<Vec<String>, int> {
    let mut seq_args = vec!();
    let program = args.get(0).clone();
    let mut iter = args.move_iter().skip(1);
    loop {
        match iter.next() {
            Some(arg) => match arg.as_slice() {
                "--help" | "-h" => {
                    print_help(&program);
                    return Err(0);
                }
                "--version" | "-V" => {
                    print_version();
                    return Err(0);
                }
                "-s" | "--separator" => match iter.next() {
                    Some(sep) => options.separator = sep,
                    None => {
                        show_error!("expected a separator after {}", arg);
                        return Err(1);
                    }
                },
                "-t" | "--terminator" => match iter.next() {
                    Some(term) => options.terminator = Some(term),
                    None => {
                        show_error!("expected a terminator after '{}'", arg);
                        return Err(1);
                    }
                },
                "-w" | "--widths" => options.widths = true,
                _ => {
                    if arg.len() > 1 && arg.as_slice().char_at(0) == '-' {
                        let argptr: *String = &arg;  // escape from the borrow checker
                        let mut chiter = unsafe { (*argptr).as_slice() }.chars().skip(1);
                        let mut ch = ' ';
                        while match chiter.next() { Some(m) => { ch = m; true } None => false } {
                            match ch {
                                'h' => {
                                    print_help(&program);
                                    return Err(0);
                                }
                                'V' => {
                                    print_version();
                                    return Err(0);
                                }
                                's' => match iter.next() {
                                    Some(sep) => {
                                        options.separator = sep;
                                        let next = chiter.next();
                                        if next.is_some() {
                                            show_error!("unexpected character ('{}')", next.unwrap());
                                            return Err(1);
                                        }
                                    }
                                    None => {
                                        show_error!("expected a separator after {}", arg);
                                        return Err(1);
                                    }
                                },
                                't' => match iter.next() {
                                    Some(term) => {
                                        options.terminator = Some(term);
                                        let next = chiter.next();
                                        if next.is_some() {
                                            show_error!("unexpected character ('{}')", next.unwrap());
                                            return Err(1);
                                        }
                                    }
                                    None => {
                                        show_error!("expected a terminator after {}", arg);
                                        return Err(1);
                                    }
                                },
                                'w' => options.widths = true,
                                _ => { seq_args.push(arg); break }
                            }
                        }
                    } else {
                        seq_args.push(arg);
                    }
                }
            },
            None => break
        }
    }
    Ok(seq_args)
}

fn print_help(program: &String) {
    let opts = [
        getopts::optopt("s", "separator", "Separator character (defaults to \\n)", ""),
        getopts::optopt("t", "terminator", "Terminator character (defaults to separator)", ""),
        getopts::optflag("w", "widths", "Equalize widths of all numbers by padding with zeros"),
        getopts::optflag("h", "help", "print this help text and exit"),
        getopts::optflag("V", "version", "print version and exit"),
    ];
    println!("seq 1.0.0\n");
    println!("Usage:\n  {} [-w] [-s string] [-t string] [first [step]] last\n", *program);
    println!("{:s}", getopts::usage("Print sequences of numbers", opts));
}

fn print_version() {
    println!("seq 1.0.0\n");
}

#[allow(dead_code)]
fn main() { os::set_exit_status(uumain(os::args())); }

pub fn uumain(args: Vec<String>) -> int {
    let program = args.get(0).clone();
    let mut options = SeqOptions {
        separator: "\n".to_string(),
        terminator: None,
        widths: false
    };
    let free = match parse_options(args, &mut options) {
        Ok(m) => m,
        Err(f) => return f
    };
    if free.len() < 1 || free.len() > 3 {
        crash!(1, "too {} operands.\nTry '{} --help' for more information.",
               if free.len() < 1 { "few" } else { "many" }, program);
    }
    let first = if free.len() > 1 {
        match parse_float(free.get(0).as_slice()) {
            Ok(n) => n,
            Err(s) => { show_error!("{:s}", s); return 1; }
        }
    } else {
        1.0
    };
    let step = if free.len() > 2 {
        match parse_float(free.get(1).as_slice()) {
            Ok(n) => n,
            Err(s) => { show_error!("{:s}", s); return 1; }
        }
    } else {
        1.0
    };
    let last = match parse_float(free.get(free.len()-1).as_slice()) {
        Ok(n) => n,
        Err(s) => { show_error!("{:s}", s); return 1; }
    };
    let separator = escape_sequences(options.separator.as_slice());
    let terminator = match options.terminator {
        Some(term) => escape_sequences(term.as_slice()),
        None => separator.clone()
    };
    print_seq(first, step, last, separator, terminator, options.widths);

    0
}

#[inline(always)]
fn done_printing(next: f64, step: f64, last: f64) -> bool {
    if step > 0f64 {
        next > last
    } else {
        next < last
    }
}

fn print_seq(first: f64, step: f64, last: f64, separator: String, terminator: String, pad: bool) {
    let mut i = first;
    let maxlen = first.max(last).to_str().len();
    while !done_printing(i, step, last) {
        let ilen = i.to_str().len();
        if pad && ilen < maxlen {
            for _ in range(0, maxlen - ilen) {
                print!("0");
            }
        }
        print!("{:f}", i);
        i += step;
        if !done_printing(i, step, last) {
            print!("{:s}", separator);
        }
    }
    if i != first {
        print!("{:s}", terminator);
    }
}
<commit_msg>seq: handle --<commit_after>#![crate_id(name="seq", vers="1.0.0", author="Daniel MacDougall")]

#![feature(macro_rules)]

// TODO: Make -w flag work with decimals
// TODO: Support -f flag

extern crate getopts;
extern crate libc;

use std::os;

#[path = "../common/util.rs"]
mod util;

static NAME: &'static str = "seq";

#[deriving(Clone)]
struct SeqOptions {
    separator: String,
    terminator: Option<String>,
    widths: bool
}

fn parse_float(s: &str) -> Result<f64, String>{
    match from_str(s) {
        Some(n) => Ok(n),
        None => Err(format!("seq: invalid floating point argument: {:s}", s))
    }
}

fn escape_sequences(s: &str) -> String {
    s.replace("\\n", "\n").
        replace("\\t", "\t")
}

fn parse_options(args: Vec<String>, options: &mut SeqOptions) -> Result<Vec<String>, int> {
    let mut seq_args = vec!();
    let program = args.get(0).clone();
    let mut iter = args.move_iter().skip(1);
    loop {
        match iter.next() {
            Some(arg) => match arg.as_slice() {
                "--help" | "-h" => {
                    print_help(&program);
                    return Err(0);
                }
                "--version" | "-V" => {
                    print_version();
                    return Err(0);
                }
                "-s" | "--separator" => match iter.next() {
                    Some(sep) => options.separator = sep,
                    None => {
                        show_error!("expected a separator after {}", arg);
                        return Err(1);
                    }
                },
                "-t" | "--terminator" => match iter.next() {
                    Some(term) => options.terminator = Some(term),
                    None => {
                        show_error!("expected a terminator after '{}'", arg);
                        return Err(1);
                    }
                },
                "-w" | "--widths" => options.widths = true,
                "--" => {
                    seq_args.push_all_move(iter.collect());
                    break;
                },
                _ => {
                    if arg.len() > 1 && arg.as_slice().char_at(0) == '-' {
                        let argptr: *String = &arg;  // escape from the borrow checker
                        let mut chiter = unsafe { (*argptr).as_slice() }.chars().skip(1);
                        let mut ch = ' ';
                        while match chiter.next() { Some(m) => { ch = m; true } None => false } {
                            match ch {
                                'h' => {
                                    print_help(&program);
                                    return Err(0);
                                }
                                'V' => {
                                    print_version();
                                    return Err(0);
                                }
                                's' => match iter.next() {
                                    Some(sep) => {
                                        options.separator = sep;
                                        let next = chiter.next();
                                        if next.is_some() {
                                            show_error!("unexpected character ('{}')", next.unwrap());
                                            return Err(1);
                                        }
                                    }
                                    None => {
                                        show_error!("expected a separator after {}", arg);
                                        return Err(1);
                                    }
                                },
                                't' => match iter.next() {
                                    Some(term) => {
                                        options.terminator = Some(term);
                                        let next = chiter.next();
                                        if next.is_some() {
                                            show_error!("unexpected character ('{}')", next.unwrap());
                                            return Err(1);
                                        }
                                    }
                                    None => {
                                        show_error!("expected a terminator after {}", arg);
                                        return Err(1);
                                    }
                                },
                                'w' => options.widths = true,
                                _ => { seq_args.push(arg); break }
                            }
                        }
                    } else {
                        seq_args.push(arg);
                    }
                }
            },
            None => break
        }
    }
    Ok(seq_args)
}

fn print_help(program: &String) {
    let opts = [
        getopts::optopt("s", "separator", "Separator character (defaults to \\n)", ""),
        getopts::optopt("t", "terminator", "Terminator character (defaults to separator)", ""),
        getopts::optflag("w", "widths", "Equalize widths of all numbers by padding with zeros"),
        getopts::optflag("h", "help", "print this help text and exit"),
        getopts::optflag("V", "version", "print version and exit"),
    ];
    println!("seq 1.0.0\n");
    println!("Usage:\n  {} [-w] [-s string] [-t string] [first [step]] last\n", *program);
    println!("{:s}", getopts::usage("Print sequences of numbers", opts));
}

fn print_version() {
    println!("seq 1.0.0\n");
}

#[allow(dead_code)]
fn main() { os::set_exit_status(uumain(os::args())); }

pub fn uumain(args: Vec<String>) -> int {
    let program = args.get(0).clone();
    let mut options = SeqOptions {
        separator: "\n".to_string(),
        terminator: None,
        widths: false
    };
    let free = match parse_options(args, &mut options) {
        Ok(m) => m,
        Err(f) => return f
    };
    if free.len() < 1 || free.len() > 3 {
        crash!(1, "too {} operands.\nTry '{} --help' for more information.",
               if free.len() < 1 { "few" } else { "many" }, program);
    }
    let first = if free.len() > 1 {
        match parse_float(free.get(0).as_slice()) {
            Ok(n) => n,
            Err(s) => { show_error!("{:s}", s); return 1; }
        }
    } else {
        1.0
    };
    let step = if free.len() > 2 {
        match parse_float(free.get(1).as_slice()) {
            Ok(n) => n,
            Err(s) => { show_error!("{:s}", s); return 1; }
        }
    } else {
        1.0
    };
    let last = match parse_float(free.get(free.len()-1).as_slice()) {
        Ok(n) => n,
        Err(s) => { show_error!("{:s}", s); return 1; }
    };
    let separator = escape_sequences(options.separator.as_slice());
    let terminator = match options.terminator {
        Some(term) => escape_sequences(term.as_slice()),
        None => separator.clone()
    };
    print_seq(first, step, last, separator, terminator, options.widths);

    0
}

#[inline(always)]
fn done_printing(next: f64, step: f64, last: f64) -> bool {
    if step > 0f64 {
        next > last
    } else {
        next < last
    }
}

fn print_seq(first: f64, step: f64, last: f64, separator: String, terminator: String, pad: bool) {
    let mut i = first;
    let maxlen = first.max(last).to_str().len();
    while !done_printing(i, step, last) {
        let ilen = i.to_str().len();
        if pad && ilen < maxlen {
            for _ in range(0, maxlen - ilen) {
                print!("0");
            }
        }
        print!("{:f}", i);
        i += step;
        if !done_printing(i, step, last) {
            print!("{:s}", separator);
        }
    }
    if i != first {
        print!("{:s}", terminator);
    }
}
<|endoftext|>


<commit_before><commit_msg>Fix detection of BNDB analysis databases<commit_after><|endoftext|>