<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::path::PathBuf;
use std::collections::BTreeMap;
use std::fs::File;

use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;
use libimagstore::storeid::StoreIdIterator;
use libimagstore::store::Store;

use toml::Value;

use error::RefErrorKind as REK;
use error::RefError as RE;
use error::ResultExt;
use error::Result;
use flags::RefFlags;
use hasher::*;
use module_path::ModuleEntryPath;
use util::*;

pub trait RefStore {

    /// Check whether there is a reference to the file at `pb`
    fn exists(&self, pb: PathBuf) -> Result<bool>;

    /// Try to get `si` as Ref object from the store
    fn get<'a>(&'a self, si: StoreId) -> Result<FileLockEntry<'a>>;

    /// Get a Ref object from the store by hash.
    ///
    /// Returns None if the hash cannot be found.
    fn get_by_hash<'a>(&'a self, hash: String) -> Result<Option<FileLockEntry<'a>>>;

    /// Delete a ref by hash
    ///
    /// If the returned Result contains an error, the ref might not be deleted.
    fn delete_by_hash(&self, hash: String) -> Result<()>;

    /// Create a Ref object which refers to `pb`
    fn create<'a>(&'a self, pb: PathBuf, flags: RefFlags) -> Result<FileLockEntry<'a>>;

    fn create_with_hasher<'a, H: Hasher>(&'a self, pb: PathBuf, flags: RefFlags, h: H)
        -> Result<FileLockEntry<'a>>;

    /// Get all reference objects
    fn all_references(&self) -> Result<StoreIdIterator>;

}

impl RefStore for Store {

    /// Check whether there is a reference to the file at `pb`
    fn exists(&self, pb: PathBuf) -> Result<bool> {
        pb.canonicalize()
            .chain_err(|| REK::PathCanonicalizationError)
            .and_then(|c| hash_path(&c))
            .chain_err(|| REK::PathHashingError)
            .and_then(|hash| {
                self.retrieve_for_module("ref").map(|iter| (hash, iter)).map_err(From::from)
            })
            .and_then(|(hash, possible_refs)| {
                // This is kind of a manual Iterator::filter() call what we do here, but with the
                // actual ::filter method we cannot return the error in a nice way, so we do it
                // manually here. If you can come up with a better version of this, feel free to
                // take this note as a todo.
                for r in possible_refs {
                    let contains_hash = try!(r.to_str()
                        .chain_err(|| REK::TypeConversionError)
                        .map(|s| s.contains(&hash[..]))
                    );

                    if !contains_hash {
                        continue;
                    }

                    match self.get(r.clone())? {
                        Some(fle) => {
                            if read_reference(&fle).map(|path| path == pb).unwrap_or(false) {
                                return Ok(true)
                            }
                        },

                        None => {
                            let e = format!("Failed to get from store: {}", r);
                            return Err(e).map_err(From::from)
                        },
                    }
                }

                Ok(false)
            })
    }

    /// Try to get `si` as Ref object from the store
    fn get<'a>(&'a self, si: StoreId) -> Result<FileLockEntry<'a>> {
        match self.get(si)? {
            None      => return Err(RE::from_kind(REK::RefNotInStore)),
            Some(fle) => Ok(fle),
        }
    }

    /// Get a Ref object from the store by hash.
    ///
    /// Returns None if the hash cannot be found.
    fn get_by_hash<'a>(&'a self, hash: String) -> Result<Option<FileLockEntry<'a>>> {
        ModuleEntryPath::new(hash)
            .into_storeid()
            .and_then(|id| self.get(id))
            .map_err(From::from)
    }

    /// Delete a ref by hash
    ///
    /// If the returned Result contains an error, the ref might not be deleted.
    fn delete_by_hash(&self, hash: String) -> Result<()> {
        ModuleEntryPath::new(hash)
            .into_storeid()
            .and_then(|id| self.delete(id))
            .map_err(From::from)
    }

    /// Create a Ref object which refers to `pb`
    fn create<'a>(&'a self, pb: PathBuf, flags: RefFlags) -> Result<FileLockEntry<'a>> {
        self.create_with_hasher(pb, flags, DefaultHasher::new())
    }

    fn create_with_hasher<'a, H: Hasher>(&'a self, pb: PathBuf, flags: RefFlags, mut h: H)
        -> Result<FileLockEntry<'a>>
    {
        use toml_query::insert::TomlValueInsertExt;

        if !pb.exists() {
            return Err(RE::from_kind(REK::RefTargetDoesNotExist));
        }
        if flags.get_content_hashing() && pb.is_dir() {
            return Err(RE::from_kind(REK::RefTargetCannotBeHashed));
        }

        let (mut fle, content_hash, permissions, canonical_path) = { // scope to be able to fold
            try!(File::open(pb.clone())
                .chain_err(|| REK::RefTargetFileCannotBeOpened)

                // If we were able to open this file,
                // we hash the contents of the file and return (file, hash)
                .and_then(|mut file| {
                    let opt_contenthash = if flags.get_content_hashing() {
                        Some(try!(h.create_hash(&pb, &mut file)))
                    } else {
                        None
                    };

                    Ok((file, opt_contenthash))
                })

                // and then we get the permissions if we have to
                // and return (file, content hash, permissions)
                .and_then(|(file, opt_contenthash)| {
                    let opt_permissions = if flags.get_permission_tracking() {
                        Some(try!(file
                                  .metadata()
                                  .map(|md| md.permissions())
                                  .chain_err(|| REK::RefTargetCannotReadPermissions)
                        ))
                    } else {
                        None
                    };

                    Ok((opt_contenthash, opt_permissions))
                })

                // and then we try to canonicalize the PathBuf, because we want to store a
                // canonicalized path
                // and return (file, content hash, permissions, canonicalized path)
                .and_then(|(opt_contenthash, opt_permissions)| {
                    pb.canonicalize()
                        .map(|can| (opt_contenthash, opt_permissions, can))
                        // if PathBuf::canonicalize() failed, build an error from the return value
                        .chain_err(|| REK::PathCanonicalizationError)
                })

                // and then we hash the canonicalized path
                // and return (file, content hash, permissions, canonicalized path, path hash)
                .and_then(|(opt_contenthash, opt_permissions, can)| {
                    let path_hash = try!(hash_path(&can).chain_err(|| REK::PathHashingError));

                    Ok((opt_contenthash, opt_permissions, can, path_hash))
                })

                // and then we convert the PathBuf of the canonicalized path to a String to be able
                // to save it in the Ref FileLockEntry obj
                // and return
                // (file, content hash, permissions, canonicalized path as String, path hash)
                .and_then(|(opt_conhash, opt_perm, can, path_hash)| {
                    match can.to_str().map(String::from) {
                        // UTF convert error in PathBuf::to_str(),
                        None      => Err(RE::from_kind(REK::PathUTF8Error)),
                        Some(can) => Ok((opt_conhash, opt_perm, can, path_hash))
                    }
                })

                // and then we create the FileLockEntry in the Store
                // and return (filelockentry, content hash, permissions, canonicalized path)
                .and_then(|(opt_conhash, opt_perm, can, path_hash)| {
                    let fle = try!(self.create(ModuleEntryPath::new(path_hash)));
                    Ok((fle, opt_conhash, opt_perm, can))
                })
            )
        };

        for tpl in [
                Some((String::from("ref"),              Value::Table(BTreeMap::new()))),
                Some((String::from("ref.permissions"),  Value::Table(BTreeMap::new()))),
                Some((String::from("ref.path"),         Value::String(canonical_path))),
                Some((String::from("ref.content_hash"), Value::Table(BTreeMap::new()))),

                content_hash.map(|hash| {
                    (format!("ref.content_hash.{}", h.hash_name()), Value::String(hash))
                }),
                permissions.map(|p| {
                    (String::from("ref.permissions.ro"), Value::Boolean(p.readonly()))
                }),
            ].into_iter()
        {
            match tpl {
                &Some((ref s, ref v)) => {
                    match fle.get_header_mut().insert(s, v.clone()) {
                        Ok(Some(_)) => {
                            let e = RE::from_kind(REK::HeaderFieldAlreadyExistsError);
                            return Err(e).chain_err(|| REK::HeaderFieldWriteError);
                        },
                        Ok(None) => {
                            // Okay, we just inserted a new header value...
                        },
                        Err(e) => return Err(e).chain_err(|| REK::HeaderFieldWriteError),
                    }
                }
                &None => {
                    debug!("Not going to insert.");
                }
            }
        }

        Ok(fle)
    }

    fn all_references(&self) -> Result<StoreIdIterator> {
        self.retrieve_for_module("ref").map_err(From::from)
    }
}

<commit_msg>Remove RefStore::get() which was simply a wrapper to Store::get()<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::path::PathBuf;
use std::collections::BTreeMap;
use std::fs::File;

use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;
use libimagstore::storeid::StoreIdIterator;
use libimagstore::store::Store;

use toml::Value;

use error::RefErrorKind as REK;
use error::RefError as RE;
use error::ResultExt;
use error::Result;
use flags::RefFlags;
use hasher::*;
use module_path::ModuleEntryPath;
use util::*;

pub trait RefStore {

    /// Check whether there is a reference to the file at `pb`
    fn exists(&self, pb: PathBuf) -> Result<bool>;

    /// Get a Ref object from the store by hash.
    ///
    /// Returns None if the hash cannot be found.
    fn get_by_hash<'a>(&'a self, hash: String) -> Result<Option<FileLockEntry<'a>>>;

    /// Delete a ref by hash
    ///
    /// If the returned Result contains an error, the ref might not be deleted.
    fn delete_by_hash(&self, hash: String) -> Result<()>;

    /// Create a Ref object which refers to `pb`
    fn create<'a>(&'a self, pb: PathBuf, flags: RefFlags) -> Result<FileLockEntry<'a>>;

    fn create_with_hasher<'a, H: Hasher>(&'a self, pb: PathBuf, flags: RefFlags, h: H)
        -> Result<FileLockEntry<'a>>;

    /// Get all reference objects
    fn all_references(&self) -> Result<StoreIdIterator>;

}

impl RefStore for Store {

    /// Check whether there is a reference to the file at `pb`
    fn exists(&self, pb: PathBuf) -> Result<bool> {
        pb.canonicalize()
            .chain_err(|| REK::PathCanonicalizationError)
            .and_then(|c| hash_path(&c))
            .chain_err(|| REK::PathHashingError)
            .and_then(|hash| {
                self.retrieve_for_module("ref").map(|iter| (hash, iter)).map_err(From::from)
            })
            .and_then(|(hash, possible_refs)| {
                // This is kind of a manual Iterator::filter() call what we do here, but with the
                // actual ::filter method we cannot return the error in a nice way, so we do it
                // manually here. If you can come up with a better version of this, feel free to
                // take this note as a todo.
                for r in possible_refs {
                    let contains_hash = try!(r.to_str()
                        .chain_err(|| REK::TypeConversionError)
                        .map(|s| s.contains(&hash[..]))
                    );

                    if !contains_hash {
                        continue;
                    }

                    match self.get(r.clone())? {
                        Some(fle) => {
                            if read_reference(&fle).map(|path| path == pb).unwrap_or(false) {
                                return Ok(true)
                            }
                        },

                        None => {
                            let e = format!("Failed to get from store: {}", r);
                            return Err(e).map_err(From::from)
                        },
                    }
                }

                Ok(false)
            })
    }

    /// Get a Ref object from the store by hash.
    ///
    /// Returns None if the hash cannot be found.
    fn get_by_hash<'a>(&'a self, hash: String) -> Result<Option<FileLockEntry<'a>>> {
        ModuleEntryPath::new(hash)
            .into_storeid()
            .and_then(|id| self.get(id))
            .map_err(From::from)
    }

    /// Delete a ref by hash
    ///
    /// If the returned Result contains an error, the ref might not be deleted.
    fn delete_by_hash(&self, hash: String) -> Result<()> {
        ModuleEntryPath::new(hash)
            .into_storeid()
            .and_then(|id| self.delete(id))
            .map_err(From::from)
    }

    /// Create a Ref object which refers to `pb`
    fn create<'a>(&'a self, pb: PathBuf, flags: RefFlags) -> Result<FileLockEntry<'a>> {
        self.create_with_hasher(pb, flags, DefaultHasher::new())
    }

    fn create_with_hasher<'a, H: Hasher>(&'a self, pb: PathBuf, flags: RefFlags, mut h: H)
        -> Result<FileLockEntry<'a>>
    {
        use toml_query::insert::TomlValueInsertExt;

        if !pb.exists() {
            return Err(RE::from_kind(REK::RefTargetDoesNotExist));
        }
        if flags.get_content_hashing() && pb.is_dir() {
            return Err(RE::from_kind(REK::RefTargetCannotBeHashed));
        }

        let (mut fle, content_hash, permissions, canonical_path) = { // scope to be able to fold
            try!(File::open(pb.clone())
                .chain_err(|| REK::RefTargetFileCannotBeOpened)

                // If we were able to open this file,
                // we hash the contents of the file and return (file, hash)
                .and_then(|mut file| {
                    let opt_contenthash = if flags.get_content_hashing() {
                        Some(try!(h.create_hash(&pb, &mut file)))
                    } else {
                        None
                    };

                    Ok((file, opt_contenthash))
                })

                // and then we get the permissions if we have to
                // and return (file, content hash, permissions)
                .and_then(|(file, opt_contenthash)| {
                    let opt_permissions = if flags.get_permission_tracking() {
                        Some(try!(file
                                  .metadata()
                                  .map(|md| md.permissions())
                                  .chain_err(|| REK::RefTargetCannotReadPermissions)
                        ))
                    } else {
                        None
                    };

                    Ok((opt_contenthash, opt_permissions))
                })

                // and then we try to canonicalize the PathBuf, because we want to store a
                // canonicalized path
                // and return (file, content hash, permissions, canonicalized path)
                .and_then(|(opt_contenthash, opt_permissions)| {
                    pb.canonicalize()
                        .map(|can| (opt_contenthash, opt_permissions, can))
                        // if PathBuf::canonicalize() failed, build an error from the return value
                        .chain_err(|| REK::PathCanonicalizationError)
                })

                // and then we hash the canonicalized path
                // and return (file, content hash, permissions, canonicalized path, path hash)
                .and_then(|(opt_contenthash, opt_permissions, can)| {
                    let path_hash = try!(hash_path(&can).chain_err(|| REK::PathHashingError));

                    Ok((opt_contenthash, opt_permissions, can, path_hash))
                })

                // and then we convert the PathBuf of the canonicalized path to a String to be able
                // to save it in the Ref FileLockEntry obj
                // and return
                // (file, content hash, permissions, canonicalized path as String, path hash)
                .and_then(|(opt_conhash, opt_perm, can, path_hash)| {
                    match can.to_str().map(String::from) {
                        // UTF convert error in PathBuf::to_str(),
                        None      => Err(RE::from_kind(REK::PathUTF8Error)),
                        Some(can) => Ok((opt_conhash, opt_perm, can, path_hash))
                    }
                })

                // and then we create the FileLockEntry in the Store
                // and return (filelockentry, content hash, permissions, canonicalized path)
                .and_then(|(opt_conhash, opt_perm, can, path_hash)| {
                    let fle = try!(self.create(ModuleEntryPath::new(path_hash)));
                    Ok((fle, opt_conhash, opt_perm, can))
                })
            )
        };

        for tpl in [
                Some((String::from("ref"),              Value::Table(BTreeMap::new()))),
                Some((String::from("ref.permissions"),  Value::Table(BTreeMap::new()))),
                Some((String::from("ref.path"),         Value::String(canonical_path))),
                Some((String::from("ref.content_hash"), Value::Table(BTreeMap::new()))),

                content_hash.map(|hash| {
                    (format!("ref.content_hash.{}", h.hash_name()), Value::String(hash))
                }),
                permissions.map(|p| {
                    (String::from("ref.permissions.ro"), Value::Boolean(p.readonly()))
                }),
            ].into_iter()
        {
            match tpl {
                &Some((ref s, ref v)) => {
                    match fle.get_header_mut().insert(s, v.clone()) {
                        Ok(Some(_)) => {
                            let e = RE::from_kind(REK::HeaderFieldAlreadyExistsError);
                            return Err(e).chain_err(|| REK::HeaderFieldWriteError);
                        },
                        Ok(None) => {
                            // Okay, we just inserted a new header value...
                        },
                        Err(e) => return Err(e).chain_err(|| REK::HeaderFieldWriteError),
                    }
                }
                &None => {
                    debug!("Not going to insert.");
                }
            }
        }

        Ok(fle)
    }

    fn all_references(&self) -> Result<StoreIdIterator> {
        self.retrieve_for_module("ref").map_err(From::from)
    }
}

<|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! HAL for Kinetis SIM module.

use super::pin;

/// Enable clock to a PORTx peripheral
#[allow(non_snake_case_functions)]
pub fn enable_PORT(port: pin::Port) {
  match port {
    pin::PortA => {reg::SIM.scgc5.set_porta(true);},
    pin::PortB => {reg::SIM.scgc5.set_portb(true);},
    pin::PortC => {reg::SIM.scgc5.set_portc(true);},
    pin::PortD => {reg::SIM.scgc5.set_portd(true);},
    pin::PortE => {reg::SIM.scgc5.set_porte(true);},
  }
}

/// Registers
#[allow(dead_code)]
pub mod reg {
  use util::volatile_cell::VolatileCell;
  use core::ops::Drop;

  ioregs!(SIM = {
    0x0    => reg32 sopt1 {
      12..15 => ramsize: ro,
      19..18 => osc32ksel,
      29     => usbvstby,
      30     => usbstby,
      31     => usbregen,
    },

    0x4    => reg32 sopt1cfg {
      24     => urwe,
      25     => uvswe,
      26     => usswe,
    },

    0x1004 => reg32 sopt2 {
      4      => rtcclkoutsel,
      5..7   => clkoutsel,
      11     => ptd7pad,
      12     => traceclksel,
      16     => pllfllsel,
      18     => usbsrc,
    },

    0x100c => reg32 sopt4 {
      0      => ftm0flt0,
      1      => ftm0flt1,
      4      => ftm1flt0,
      18..19 => ftm1ch0src,
      24     => ftm0clksel,
      25     => ftm1clksel,
      28     => ftm0trg0src,
    },

    0x1010 => reg32 sopt5 {
      0      => uart0txsrc,
      2..3   => uart0rxsrc,
      4      => uart1txsrc,
      6..7   => uart1rxsrc,
    },

    0x1018 => reg32 sopt7 {
      0..3   => adc0trgsel {
        0x0 => PDB0_EXTRG,
        0x1 => CMP0_OUT,
        0x2 => CMP1_OUT,
        // reserved
        0x4 => PIT_TRG0,
        0x5 => PIT_TRG1,
        0x6 => PIT_TRG2,
        0x7 => PIT_TRG3,
        0x8 => FTM0_TRG,
        0x9 => FTM1_TRG,
        // unused
        // unused
        0x12 => RTC_ALARM,
        0x13 => RTC_SECONDS,
        0x14 => LPT_TRG,
        // unused
      },
      4      => adc0pretrgsel,
      7      => adc0alttrgen,
    },

    0x1034 => reg32 scgc4 {
      1      => ewm,
      2      => cmt,
      6      => i2c0,
      10     => uart0,
      11     => uart1,
      12     => uart2,
      18     => usbotg,
      19     => cmp,
      20     => vreg,
    },

    0x1038 => reg32 scgc5 {
      0      => lptimer,
      5      => tsi,
      9      => porta,
      10     => portb,
      11     => portc,
      12     => portd,
      13     => porte,
    },

    0x103c => reg32 scgc6 {
      0      => ftfl,
      1      => dmamux,
      12     => spi0,
      15     => i2s,
      18     => crc,
      21     => usbdcd,
      22     => pdb,
      23     => pit,
      24     => ftm0,
      25     => ftm1,
      27     => adc0,
      29     => rtc,
    },

    0x1040 => reg32 scgc7 {
      1      => dma,
    },

    0x1044 => reg32 clkdiv1 {
      16..19 => outdiv4,
      24..27 => outdiv2,
      28..31 => outdiv1,
    },

    0x1048 => reg32 clkdiv2 {
      0      => usbfrac,
      1..3   => usbdiv,
    },

    0x104c => reg32 fcfg1 {
      0      => flashdis,
      1      => flashdoze,
      8..11  => depart,
      16..19 => eesize,
      24..27 => pfsize,
      28..31 => nvmsize,
    },

    0x1050 => reg32 fcfg2 {
      16..22 => maxaddr1,
      23     => pflsh,
      24..30 => maxaddr0,
    },

    0x1058 => reg32 uidmh {
      0..31  => uid,
    },

    0x1060 => reg32 uidl {
      0..31  => uid,
    },
  })

  extern {
    #[link_name="k20_iomem_SIM"] pub static SIM: SIM;
  }
}
<commit_msg>k20::sim: Fix non-snake-case warning<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! HAL for Kinetis SIM module.

use super::pin;

/// Enable clock to a PORTx peripheral
#[allow(non_snake_case)]
pub fn enable_PORT(port: pin::Port) {
  match port {
    pin::PortA => {reg::SIM.scgc5.set_porta(true);},
    pin::PortB => {reg::SIM.scgc5.set_portb(true);},
    pin::PortC => {reg::SIM.scgc5.set_portc(true);},
    pin::PortD => {reg::SIM.scgc5.set_portd(true);},
    pin::PortE => {reg::SIM.scgc5.set_porte(true);},
  }
}

/// Registers
#[allow(dead_code)]
pub mod reg {
  use util::volatile_cell::VolatileCell;
  use core::ops::Drop;

  ioregs!(SIM = {
    0x0    => reg32 sopt1 {
      12..15 => ramsize: ro,
      19..18 => osc32ksel,
      29     => usbvstby,
      30     => usbstby,
      31     => usbregen,
    },

    0x4    => reg32 sopt1cfg {
      24     => urwe,
      25     => uvswe,
      26     => usswe,
    },

    0x1004 => reg32 sopt2 {
      4      => rtcclkoutsel,
      5..7   => clkoutsel,
      11     => ptd7pad,
      12     => traceclksel,
      16     => pllfllsel,
      18     => usbsrc,
    },

    0x100c => reg32 sopt4 {
      0      => ftm0flt0,
      1      => ftm0flt1,
      4      => ftm1flt0,
      18..19 => ftm1ch0src,
      24     => ftm0clksel,
      25     => ftm1clksel,
      28     => ftm0trg0src,
    },

    0x1010 => reg32 sopt5 {
      0      => uart0txsrc,
      2..3   => uart0rxsrc,
      4      => uart1txsrc,
      6..7   => uart1rxsrc,
    },

    0x1018 => reg32 sopt7 {
      0..3   => adc0trgsel {
        0x0 => PDB0_EXTRG,
        0x1 => CMP0_OUT,
        0x2 => CMP1_OUT,
        // reserved
        0x4 => PIT_TRG0,
        0x5 => PIT_TRG1,
        0x6 => PIT_TRG2,
        0x7 => PIT_TRG3,
        0x8 => FTM0_TRG,
        0x9 => FTM1_TRG,
        // unused
        // unused
        0x12 => RTC_ALARM,
        0x13 => RTC_SECONDS,
        0x14 => LPT_TRG,
        // unused
      },
      4      => adc0pretrgsel,
      7      => adc0alttrgen,
    },

    0x1034 => reg32 scgc4 {
      1      => ewm,
      2      => cmt,
      6      => i2c0,
      10     => uart0,
      11     => uart1,
      12     => uart2,
      18     => usbotg,
      19     => cmp,
      20     => vreg,
    },

    0x1038 => reg32 scgc5 {
      0      => lptimer,
      5      => tsi,
      9      => porta,
      10     => portb,
      11     => portc,
      12     => portd,
      13     => porte,
    },

    0x103c => reg32 scgc6 {
      0      => ftfl,
      1      => dmamux,
      12     => spi0,
      15     => i2s,
      18     => crc,
      21     => usbdcd,
      22     => pdb,
      23     => pit,
      24     => ftm0,
      25     => ftm1,
      27     => adc0,
      29     => rtc,
    },

    0x1040 => reg32 scgc7 {
      1      => dma,
    },

    0x1044 => reg32 clkdiv1 {
      16..19 => outdiv4,
      24..27 => outdiv2,
      28..31 => outdiv1,
    },

    0x1048 => reg32 clkdiv2 {
      0      => usbfrac,
      1..3   => usbdiv,
    },

    0x104c => reg32 fcfg1 {
      0      => flashdis,
      1      => flashdoze,
      8..11  => depart,
      16..19 => eesize,
      24..27 => pfsize,
      28..31 => nvmsize,
    },

    0x1050 => reg32 fcfg2 {
      16..22 => maxaddr1,
      23     => pflsh,
      24..30 => maxaddr0,
    },

    0x1058 => reg32 uidmh {
      0..31  => uid,
    },

    0x1060 => reg32 uidl {
      0..31  => uid,
    },
  })

  extern {
    #[link_name="k20_iomem_SIM"] pub static SIM: SIM;
  }
}
<|endoftext|>


<commit_before><commit_msg>fix global config capacity<commit_after><|endoftext|>


<commit_before>//! `hermit-abi` is small interface to call functions from the unikernel
//! [RustyHermit](https://github.com/hermitcore/libhermit-rs).

#![cfg_attr(feature = "rustc-dep-of-std", no_std)]
#![feature(const_raw_ptr_to_usize_cast)]
extern crate libc;

pub mod tcpstream;

use libc::c_void;

// sysmbols, which are part of the library operating system
extern "C" {
	fn sys_get_processor_count() -> usize;
	fn sys_malloc(size: usize, align: usize) -> *mut u8;
	fn sys_realloc(ptr: *mut u8, size: usize, align: usize, new_size: usize) -> *mut u8;
	fn sys_free(ptr: *mut u8, size: usize, align: usize);
	fn sys_notify(id: usize, count: i32) -> i32;
	fn sys_add_queue(id: usize, timeout_ns: i64) -> i32;
	fn sys_wait(id: usize) -> i32;
	fn sys_destroy_queue(id: usize) -> i32;
	fn sys_read(fd: i32, buf: *mut u8, len: usize) -> isize;
	fn sys_write(fd: i32, buf: *const u8, len: usize) -> isize;
	fn sys_close(fd: i32) -> i32;
	fn sys_sem_init(sem: *mut *const c_void, value: u32) -> i32;
	fn sys_sem_destroy(sem: *const c_void) -> i32;
	fn sys_sem_post(sem: *const c_void) -> i32;
	fn sys_sem_trywait(sem: *const c_void) -> i32;
	fn sys_sem_timedwait(sem: *const c_void, ms: u32) -> i32;
	fn sys_recmutex_init(recmutex: *mut *const c_void) -> i32;
	fn sys_recmutex_destroy(recmutex: *const c_void) -> i32;
	fn sys_recmutex_lock(recmutex: *const c_void) -> i32;
	fn sys_recmutex_unlock(recmutex: *const c_void) -> i32;
	fn sys_getpid() -> u32;
	fn sys_exit(arg: i32) -> !;
	fn sys_abort() -> !;
	fn sys_usleep(usecs: u64);
	fn sys_spawn(
		id: *mut Tid,
		func: extern "C" fn(usize),
		arg: usize,
		prio: u8,
		core_id: isize,
	) -> i32;
	fn sys_spawn2(
		id: *mut Tid,
		func: extern "C" fn(usize),
		arg: usize,
		prio: u8,
		stack_size: usize,
		core_id: isize,
	) -> i32;
	fn sys_join(id: Tid) -> i32;
	fn sys_yield();
	fn sys_clock_gettime(clock_id: u64, tp: *mut timespec) -> i32;
	fn sys_open(name: *const i8, flags: i32, mode: i32) -> i32;
	fn sys_unlink(name: *const i8) -> i32;
	fn sys_network_init() -> i32;
}

/// A thread handle type
pub type Tid = u32;

/// Priority of a thread
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
pub struct Priority(u8);

impl Priority {
	pub const fn into(self) -> u8 {
		self.0
	}

	pub const fn from(x: u8) -> Self {
		Priority(x)
	}
}

pub const HIGH_PRIO: Priority = Priority::from(3);
pub const NORMAL_PRIO: Priority = Priority::from(2);
pub const LOW_PRIO: Priority = Priority::from(1);

/// A handle, identifying a socket
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
pub struct Handle(usize);

pub const NSEC_PER_SEC: u64 = 1_000_000_000;
pub const CLOCK_REALTIME: u64 = 1;
pub const CLOCK_MONOTONIC: u64 = 4;
pub const STDIN_FILENO: libc::c_int = 0;
pub const STDOUT_FILENO: libc::c_int = 1;
pub const STDERR_FILENO: libc::c_int = 2;
pub const O_RDONLY: i32 = 0o0;
pub const O_WRONLY: i32 = 0o1;
pub const O_RDWR: i32 = 0o2;
pub const O_CREAT: i32 = 0o100;
pub const O_EXCL: i32 = 0o200;
pub const O_TRUNC: i32 = 0o1000;
pub const O_APPEND: i32 = 0o2000;

/// returns true if file descriptor `fd` is a tty
pub fn isatty(_fd: libc::c_int) -> bool {
	false
}

/// intialize the network stack
pub fn network_init() -> i32 {
	unsafe { sys_network_init() }
}

/// `timespec` is used by `clock_gettime` to retrieve the
/// current time
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct timespec {
	/// seconds
	pub tv_sec: i64,
	/// nanoseconds
	pub tv_nsec: i64,
}

/// determines the number of activated processors
#[inline(always)]
pub unsafe fn get_processor_count() -> usize {
	sys_get_processor_count()
}

#[doc(hidden)]
#[inline(always)]
pub unsafe fn malloc(size: usize, align: usize) -> *mut u8 {
	sys_malloc(size, align)
}

#[doc(hidden)]
#[inline(always)]
pub unsafe fn realloc(ptr: *mut u8, size: usize, align: usize, new_size: usize) -> *mut u8 {
	sys_realloc(ptr, size, align, new_size)
}

#[doc(hidden)]
#[inline(always)]
pub unsafe fn free(ptr: *mut u8, size: usize, align: usize) {
	sys_free(ptr, size, align)
}

#[inline(always)]
pub unsafe fn notify(id: usize, count: i32) -> i32 {
	sys_notify(id, count)
}

#[doc(hidden)]
#[inline(always)]
pub unsafe fn add_queue(id: usize, timeout_ns: i64) -> i32 {
	sys_add_queue(id, timeout_ns)
}

#[doc(hidden)]
#[inline(always)]
pub unsafe fn wait(id: usize) -> i32 {
	sys_wait(id)
}

#[doc(hidden)]
#[inline(always)]
pub unsafe fn destroy_queue(id: usize) -> i32 {
	sys_destroy_queue(id)
}

/// read from a file descriptor
///
/// read() attempts to read `len` bytes of data from the object
/// referenced by the descriptor `fd` into the buffer pointed
/// to by `buf`.
#[inline(always)]
pub unsafe fn read(fd: i32, buf: *mut u8, len: usize) -> isize {
	sys_read(fd, buf, len)
}

/// write to a file descriptor
///
/// write() attempts to write `len` of data to the object
/// referenced by the descriptor `fd` from the
/// buffer pointed to by `buf`.
#[inline(always)]
pub unsafe fn write(fd: i32, buf: *const u8, len: usize) -> isize {
	sys_write(fd, buf, len)
}

/// close a file descriptor
///
/// The close() call deletes a file descriptor `fd` from the object
/// reference table.
#[inline(always)]
pub unsafe fn close(fd: i32) -> i32 {
	sys_close(fd)
}

/// sem_init() initializes the unnamed semaphore at the address
/// pointed to by `sem`.  The `value` argument specifies the
/// initial value for the semaphore.
#[inline(always)]
pub unsafe fn sem_init(sem: *mut *const c_void, value: u32) -> i32 {
	sys_sem_init(sem, value)
}

/// sem_destroy() frees the unnamed semaphore at the address
/// pointed to by `sem`.
#[inline(always)]
pub unsafe fn sem_destroy(sem: *const c_void) -> i32 {
	sys_sem_destroy(sem)
}

/// sem_post() increments the semaphore pointed to by `sem`.
/// If the semaphore's value consequently becomes greater
/// than zero, then another thread blocked in a sem_wait call
/// will be woken up and proceed to lock the semaphore.
#[inline(always)]
pub unsafe fn sem_post(sem: *const c_void) -> i32 {
	sys_sem_post(sem)
}

/// try to decrement a semaphore
///
/// sem_trywait() is the same as sem_timedwait(), except that
/// if the  decrement cannot be immediately performed, then  call
/// returns a negative value instead of blocking.
#[inline(always)]
pub unsafe fn sem_trywait(sem: *const c_void) -> i32 {
	sys_sem_trywait(sem)
}

/// decrement a semaphore
///
/// sem_timedwait() decrements the semaphore pointed to by `sem`.
/// If the semaphore's value is greater than zero, then the
/// the function returns immediately. If the semaphore currently
/// has the value zero, then the call blocks until either
/// it becomes possible to perform the decrement of the time limit
/// to wait for the semaphore is expired. A time limit `ms` of
/// means infinity waiting time.
#[inline(always)]
pub unsafe fn sem_timedwait(sem: *const c_void, ms: u32) -> i32 {
	sys_sem_timedwait(sem, ms)
}

#[doc(hidden)]
#[inline(always)]
pub unsafe fn recmutex_init(recmutex: *mut *const c_void) -> i32 {
	sys_recmutex_init(recmutex)
}

#[doc(hidden)]
#[inline(always)]
pub unsafe fn recmutex_destroy(recmutex: *const c_void) -> i32 {
	sys_recmutex_destroy(recmutex)
}

#[doc(hidden)]
#[inline(always)]
pub unsafe fn recmutex_lock(recmutex: *const c_void) -> i32 {
	sys_recmutex_lock(recmutex)
}

#[doc(hidden)]
#[inline(always)]
pub unsafe fn recmutex_unlock(recmutex: *const c_void) -> i32 {
	sys_recmutex_unlock(recmutex)
}

/// Determines the id of the current thread
#[inline(always)]
pub unsafe fn getpid() -> u32 {
	sys_getpid()
}

/// cause normal termination and return `arg`
/// to the host system
#[inline(always)]
pub unsafe fn exit(arg: i32) -> ! {
	sys_exit(arg)
}

/// cause abnormal termination
#[inline(always)]
pub unsafe fn abort() -> ! {
	sys_abort()
}

/// suspend execution for microsecond intervals
///
/// The usleep() function suspends execution of the calling
/// thread for (at least) `usecs` microseconds.
#[inline(always)]
pub unsafe fn usleep(usecs: u64) {
	sys_usleep(usecs)
}

/// spawn a new thread
///
/// spawn() starts a new thread. The new thread starts execution
/// by invoking `func(usize)`; `arg` is passed as the argument
/// to `func`. `prio` defines the priority of the new thread,
/// which can be between `LOW_PRIO` and `HIGH_PRIO`.
/// `core_id` defines the core, where the thread is located.
/// A negative value give the operating system the possibility
/// to select the core by its own.
#[inline(always)]
pub unsafe fn spawn(
	id: *mut Tid,
	func: extern "C" fn(usize),
	arg: usize,
	prio: u8,
	core_id: isize,
) -> i32 {
	sys_spawn(id, func, arg, prio, core_id)
}

/// spawn a new thread with user-specified stack size
///
/// spawn2() starts a new thread. The new thread starts execution
/// by invoking `func(usize)`; `arg` is passed as the argument
/// to `func`. `prio` defines the priority of the new thread,
/// which can be between `LOW_PRIO` and `HIGH_PRIO`.
/// `core_id` defines the core, where the thread is located.
/// A negative value give the operating system the possibility
/// to select the core by its own.
/// In contrast to spawn(), spawn2() is able to define the
/// stack size.
#[inline(always)]
pub unsafe fn spawn2(
	id: *mut Tid,
	func: extern "C" fn(usize),
	arg: usize,
	prio: u8,
	stack_size: usize,
	core_id: isize,
) -> i32 {
	sys_spawn2(id, func, arg, prio, stack_size, core_id)
}

/// join with a terminated thread
///
/// The join() function waits for the thread specified by `id`
/// to terminate.
#[inline(always)]
pub unsafe fn join(id: Tid) -> i32 {
	sys_join(id)
}

/// yield the processor
///
/// causes the calling thread to relinquish the CPU. The thread
/// is moved to the end of the queue for its static priority.
#[inline(always)]
pub unsafe fn yield_now() {
	sys_yield()
}

/// get current time
///
/// The clock_gettime() functions allow the calling thread
/// to retrieve the value used by a clock which is specified
/// by `clock_id`.
///
/// `CLOCK_REALTIME`: the system's real time clock,
/// expressed as the amount of time since the Epoch.
///
/// `CLOCK_MONOTONIC`: clock that increments monotonically,
/// tracking the time since an arbitrary point
#[inline(always)]
pub unsafe fn clock_gettime(clock_id: u64, tp: *mut timespec) -> i32 {
	sys_clock_gettime(clock_id, tp)
}

/// open and possibly create a file
///
/// The open() system call opens the file specified by `name`.
/// If the specified file does not exist, it may optionally
/// be created by open().
#[inline(always)]
pub unsafe fn open(name: *const i8, flags: i32, mode: i32) -> i32 {
	sys_open(name, flags, mode)
}

/// delete the file it refers to `name`
#[inline(always)]
pub unsafe fn unlink(name: *const i8) -> i32 {
	sys_unlink(name)
}
<commit_msg>avoid using of more than 5 arguments<commit_after>//! `hermit-abi` is small interface to call functions from the unikernel
//! [RustyHermit](https://github.com/hermitcore/libhermit-rs).

#![cfg_attr(feature = "rustc-dep-of-std", no_std)]
#![feature(const_raw_ptr_to_usize_cast)]
extern crate libc;

pub mod tcpstream;

use libc::c_void;

// sysmbols, which are part of the library operating system
extern "C" {
	fn sys_get_processor_count() -> usize;
	fn sys_malloc(size: usize, align: usize) -> *mut u8;
	fn sys_realloc(ptr: *mut u8, size: usize, align: usize, new_size: usize) -> *mut u8;
	fn sys_free(ptr: *mut u8, size: usize, align: usize);
	fn sys_notify(id: usize, count: i32) -> i32;
	fn sys_add_queue(id: usize, timeout_ns: i64) -> i32;
	fn sys_wait(id: usize) -> i32;
	fn sys_destroy_queue(id: usize) -> i32;
	fn sys_read(fd: i32, buf: *mut u8, len: usize) -> isize;
	fn sys_write(fd: i32, buf: *const u8, len: usize) -> isize;
	fn sys_close(fd: i32) -> i32;
	fn sys_sem_init(sem: *mut *const c_void, value: u32) -> i32;
	fn sys_sem_destroy(sem: *const c_void) -> i32;
	fn sys_sem_post(sem: *const c_void) -> i32;
	fn sys_sem_trywait(sem: *const c_void) -> i32;
	fn sys_sem_timedwait(sem: *const c_void, ms: u32) -> i32;
	fn sys_recmutex_init(recmutex: *mut *const c_void) -> i32;
	fn sys_recmutex_destroy(recmutex: *const c_void) -> i32;
	fn sys_recmutex_lock(recmutex: *const c_void) -> i32;
	fn sys_recmutex_unlock(recmutex: *const c_void) -> i32;
	fn sys_getpid() -> u32;
	fn sys_exit(arg: i32) -> !;
	fn sys_abort() -> !;
	fn sys_usleep(usecs: u64);
	fn sys_spawn(
		id: *mut Tid,
		func: extern "C" fn(usize),
		arg: usize,
		prio: u8,
		core_id: isize,
	) -> i32;
	fn sys_spawn2(
		func: extern "C" fn(usize),
		arg: usize,
		prio: u8,
		stack_size: usize,
		core_id: isize,
	) -> Tid;
	fn sys_join(id: Tid) -> i32;
	fn sys_yield();
	fn sys_clock_gettime(clock_id: u64, tp: *mut timespec) -> i32;
	fn sys_open(name: *const i8, flags: i32, mode: i32) -> i32;
	fn sys_unlink(name: *const i8) -> i32;
	fn sys_network_init() -> i32;
}

/// A thread handle type
pub type Tid = u32;

/// Priority of a thread
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
pub struct Priority(u8);

impl Priority {
	pub const fn into(self) -> u8 {
		self.0
	}

	pub const fn from(x: u8) -> Self {
		Priority(x)
	}
}

pub const HIGH_PRIO: Priority = Priority::from(3);
pub const NORMAL_PRIO: Priority = Priority::from(2);
pub const LOW_PRIO: Priority = Priority::from(1);

/// A handle, identifying a socket
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
pub struct Handle(usize);

pub const NSEC_PER_SEC: u64 = 1_000_000_000;
pub const CLOCK_REALTIME: u64 = 1;
pub const CLOCK_MONOTONIC: u64 = 4;
pub const STDIN_FILENO: libc::c_int = 0;
pub const STDOUT_FILENO: libc::c_int = 1;
pub const STDERR_FILENO: libc::c_int = 2;
pub const O_RDONLY: i32 = 0o0;
pub const O_WRONLY: i32 = 0o1;
pub const O_RDWR: i32 = 0o2;
pub const O_CREAT: i32 = 0o100;
pub const O_EXCL: i32 = 0o200;
pub const O_TRUNC: i32 = 0o1000;
pub const O_APPEND: i32 = 0o2000;

/// returns true if file descriptor `fd` is a tty
pub fn isatty(_fd: libc::c_int) -> bool {
	false
}

/// intialize the network stack
pub fn network_init() -> i32 {
	unsafe { sys_network_init() }
}

/// `timespec` is used by `clock_gettime` to retrieve the
/// current time
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct timespec {
	/// seconds
	pub tv_sec: i64,
	/// nanoseconds
	pub tv_nsec: i64,
}

/// determines the number of activated processors
#[inline(always)]
pub unsafe fn get_processor_count() -> usize {
	sys_get_processor_count()
}

#[doc(hidden)]
#[inline(always)]
pub unsafe fn malloc(size: usize, align: usize) -> *mut u8 {
	sys_malloc(size, align)
}

#[doc(hidden)]
#[inline(always)]
pub unsafe fn realloc(ptr: *mut u8, size: usize, align: usize, new_size: usize) -> *mut u8 {
	sys_realloc(ptr, size, align, new_size)
}

#[doc(hidden)]
#[inline(always)]
pub unsafe fn free(ptr: *mut u8, size: usize, align: usize) {
	sys_free(ptr, size, align)
}

#[inline(always)]
pub unsafe fn notify(id: usize, count: i32) -> i32 {
	sys_notify(id, count)
}

#[doc(hidden)]
#[inline(always)]
pub unsafe fn add_queue(id: usize, timeout_ns: i64) -> i32 {
	sys_add_queue(id, timeout_ns)
}

#[doc(hidden)]
#[inline(always)]
pub unsafe fn wait(id: usize) -> i32 {
	sys_wait(id)
}

#[doc(hidden)]
#[inline(always)]
pub unsafe fn destroy_queue(id: usize) -> i32 {
	sys_destroy_queue(id)
}

/// read from a file descriptor
///
/// read() attempts to read `len` bytes of data from the object
/// referenced by the descriptor `fd` into the buffer pointed
/// to by `buf`.
#[inline(always)]
pub unsafe fn read(fd: i32, buf: *mut u8, len: usize) -> isize {
	sys_read(fd, buf, len)
}

/// write to a file descriptor
///
/// write() attempts to write `len` of data to the object
/// referenced by the descriptor `fd` from the
/// buffer pointed to by `buf`.
#[inline(always)]
pub unsafe fn write(fd: i32, buf: *const u8, len: usize) -> isize {
	sys_write(fd, buf, len)
}

/// close a file descriptor
///
/// The close() call deletes a file descriptor `fd` from the object
/// reference table.
#[inline(always)]
pub unsafe fn close(fd: i32) -> i32 {
	sys_close(fd)
}

/// sem_init() initializes the unnamed semaphore at the address
/// pointed to by `sem`.  The `value` argument specifies the
/// initial value for the semaphore.
#[inline(always)]
pub unsafe fn sem_init(sem: *mut *const c_void, value: u32) -> i32 {
	sys_sem_init(sem, value)
}

/// sem_destroy() frees the unnamed semaphore at the address
/// pointed to by `sem`.
#[inline(always)]
pub unsafe fn sem_destroy(sem: *const c_void) -> i32 {
	sys_sem_destroy(sem)
}

/// sem_post() increments the semaphore pointed to by `sem`.
/// If the semaphore's value consequently becomes greater
/// than zero, then another thread blocked in a sem_wait call
/// will be woken up and proceed to lock the semaphore.
#[inline(always)]
pub unsafe fn sem_post(sem: *const c_void) -> i32 {
	sys_sem_post(sem)
}

/// try to decrement a semaphore
///
/// sem_trywait() is the same as sem_timedwait(), except that
/// if the  decrement cannot be immediately performed, then  call
/// returns a negative value instead of blocking.
#[inline(always)]
pub unsafe fn sem_trywait(sem: *const c_void) -> i32 {
	sys_sem_trywait(sem)
}

/// decrement a semaphore
///
/// sem_timedwait() decrements the semaphore pointed to by `sem`.
/// If the semaphore's value is greater than zero, then the
/// the function returns immediately. If the semaphore currently
/// has the value zero, then the call blocks until either
/// it becomes possible to perform the decrement of the time limit
/// to wait for the semaphore is expired. A time limit `ms` of
/// means infinity waiting time.
#[inline(always)]
pub unsafe fn sem_timedwait(sem: *const c_void, ms: u32) -> i32 {
	sys_sem_timedwait(sem, ms)
}

#[doc(hidden)]
#[inline(always)]
pub unsafe fn recmutex_init(recmutex: *mut *const c_void) -> i32 {
	sys_recmutex_init(recmutex)
}

#[doc(hidden)]
#[inline(always)]
pub unsafe fn recmutex_destroy(recmutex: *const c_void) -> i32 {
	sys_recmutex_destroy(recmutex)
}

#[doc(hidden)]
#[inline(always)]
pub unsafe fn recmutex_lock(recmutex: *const c_void) -> i32 {
	sys_recmutex_lock(recmutex)
}

#[doc(hidden)]
#[inline(always)]
pub unsafe fn recmutex_unlock(recmutex: *const c_void) -> i32 {
	sys_recmutex_unlock(recmutex)
}

/// Determines the id of the current thread
#[inline(always)]
pub unsafe fn getpid() -> u32 {
	sys_getpid()
}

/// cause normal termination and return `arg`
/// to the host system
#[inline(always)]
pub unsafe fn exit(arg: i32) -> ! {
	sys_exit(arg)
}

/// cause abnormal termination
#[inline(always)]
pub unsafe fn abort() -> ! {
	sys_abort()
}

/// suspend execution for microsecond intervals
///
/// The usleep() function suspends execution of the calling
/// thread for (at least) `usecs` microseconds.
#[inline(always)]
pub unsafe fn usleep(usecs: u64) {
	sys_usleep(usecs)
}

/// spawn a new thread
///
/// spawn() starts a new thread. The new thread starts execution
/// by invoking `func(usize)`; `arg` is passed as the argument
/// to `func`. `prio` defines the priority of the new thread,
/// which can be between `LOW_PRIO` and `HIGH_PRIO`.
/// `core_id` defines the core, where the thread is located.
/// A negative value give the operating system the possibility
/// to select the core by its own.
#[inline(always)]
pub unsafe fn spawn(
	id: *mut Tid,
	func: extern "C" fn(usize),
	arg: usize,
	prio: u8,
	core_id: isize,
) -> i32 {
	sys_spawn(id, func, arg, prio, core_id)
}

/// spawn a new thread with user-specified stack size
///
/// spawn2() starts a new thread. The new thread starts execution
/// by invoking `func(usize)`; `arg` is passed as the argument
/// to `func`. `prio` defines the priority of the new thread,
/// which can be between `LOW_PRIO` and `HIGH_PRIO`.
/// `core_id` defines the core, where the thread is located.
/// A negative value give the operating system the possibility
/// to select the core by its own.
/// In contrast to spawn(), spawn2() is able to define the
/// stack size.
#[inline(always)]
pub unsafe fn spawn2(
	func: extern "C" fn(usize),
	arg: usize,
	prio: u8,
	stack_size: usize,
	core_id: isize,
) -> Tid {
	sys_spawn2(func, arg, prio, stack_size, core_id)
}

/// join with a terminated thread
///
/// The join() function waits for the thread specified by `id`
/// to terminate.
#[inline(always)]
pub unsafe fn join(id: Tid) -> i32 {
	sys_join(id)
}

/// yield the processor
///
/// causes the calling thread to relinquish the CPU. The thread
/// is moved to the end of the queue for its static priority.
#[inline(always)]
pub unsafe fn yield_now() {
	sys_yield()
}

/// get current time
///
/// The clock_gettime() functions allow the calling thread
/// to retrieve the value used by a clock which is specified
/// by `clock_id`.
///
/// `CLOCK_REALTIME`: the system's real time clock,
/// expressed as the amount of time since the Epoch.
///
/// `CLOCK_MONOTONIC`: clock that increments monotonically,
/// tracking the time since an arbitrary point
#[inline(always)]
pub unsafe fn clock_gettime(clock_id: u64, tp: *mut timespec) -> i32 {
	sys_clock_gettime(clock_id, tp)
}

/// open and possibly create a file
///
/// The open() system call opens the file specified by `name`.
/// If the specified file does not exist, it may optionally
/// be created by open().
#[inline(always)]
pub unsafe fn open(name: *const i8, flags: i32, mode: i32) -> i32 {
	sys_open(name, flags, mode)
}

/// delete the file it refers to `name`
#[inline(always)]
pub unsafe fn unlink(name: *const i8) -> i32 {
	sys_unlink(name)
}
<|endoftext|>


<commit_before>
extern crate getopts;
extern crate time;
extern crate toml;
extern crate plugwise;

use std::env;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path;
use std::collections::HashMap;

use getopts::Options;

use time::Duration;

use plugwise::Device;
use plugwise::ProtocolSnoop;
use plugwise::plugwise;

const CONFIG: &'static str = ".plugwise.toml";
const CONFIG_HEAD: &'static str = "config";
const CONFIG_DEVICE: &'static str = "device";
const ALIAS_MAC: &'static str = "mac";

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options] [mac|alias]", program);
    println!("{}", opts.usage(&brief));
}

fn load_config(configfile: &path::PathBuf) -> toml::Table {
    let mut config = String::new();
    if let Ok(mut file) = File::open(configfile) {
        file.read_to_string(&mut config).ok().expect(
            &format!("unable to read file `{}`", configfile.display()));
    } // errors are silently ignored (assuming file didn't exist)
    toml::Parser::new(&config).parse().expect(&format!("unable to parse `{}`", configfile.display()))
}

fn write_config(configfile: &path::PathBuf, config: &toml::Table) {
    let mut file = File::create(configfile).ok().expect(
        &format!("unable to create `{}`", configfile.display()));
    write!(file, "{}", toml::Value::Table(config.clone())).ok().expect(
        &format!("unable to write to `{}`", configfile.display()));
}

fn get_device_from_config<'a>(config: &'a toml::Table) -> Option<String> {
    config.get(CONFIG_HEAD)
          .map_or(None, |item|item.as_table())
          .map_or(None, |table|table.get(CONFIG_DEVICE))
          .map_or(None, |string|string.as_str())
          .map(|string|string.to_string())
}

fn get_aliases<'a>(config: &'a toml::Table) -> HashMap<String, u64> {
    let mut aliases = HashMap::new();

    for key in config.keys().filter(|&k|k != CONFIG_HEAD) {
        let mac = config.get(key)
                        .map_or(None, |item|item.as_table())
                        .map_or(None, |table|table.get(ALIAS_MAC))
                        .map_or(None, |string|string.as_str());
        if let Some(mac) = mac {
            if mac.len() == 16 {
                let mac = u64::from_str_radix(&mac, 16);
                if let Ok(mac) = mac {
                    aliases.insert(key.to_string(), mac);
                }
            }
        }
    }

    aliases
}

fn update_device_from_config<'a>(config: &'a toml::Table, device: &'a str) -> toml::Table {
    let mut config_table = config.get(CONFIG_HEAD)
                                 .map_or(None, |item|item.as_table())
                                 .map_or(toml::Table::new(), |table|table.clone());
    config_table.insert(CONFIG_DEVICE.to_string(), toml::Value::String(device.to_string()));
    config_table
}

fn remove_device_from_config<'a>(config: &'a toml::Table) -> toml::Table {
    let mut config_table = config.get(CONFIG_HEAD)
                                 .map_or(None, |item|item.as_table())
                                 .map_or(toml::Table::new(), |table|table.clone());
    config_table.remove(CONFIG_DEVICE);
    config_table
}

fn update_mac_in_alias<'a>(config: &'a toml::Table, alias: &'a str, mac: u64) -> toml::Table {
    let mut config_table = config.get(alias)
                                 .map_or(None, |item|item.as_table())
                                 .map_or(toml::Table::new(), |table|table.clone());
    config_table.insert(ALIAS_MAC.to_string(), toml::Value::String(format!("{:016X}", mac)));
    config_table
}

fn plugwise_actions(matches: &getopts::Matches, serial: Option<String>, mac: u64) {
    let mut debug = io::stdout();
    let snoop = match matches.opt_count("v") {
        0 => ProtocolSnoop::Nothing,
        1 => ProtocolSnoop::Debug(&mut debug),
        2 => ProtocolSnoop::Raw(&mut debug),
        _ => ProtocolSnoop::All(&mut debug)
    };
    let device = match serial {
        Some(ref serial) => Device::SerialExt{port: &serial,
                                              timeout: Duration::milliseconds(1000),
                                              retries: 3,
                                              snoop: snoop},
        None => Device::Simulator
    };
    let plugwise = plugwise(device).ok().expect("unable to connect to Plugwise device");
    let circle = plugwise.create_circle(mac).ok().expect("unable to connect to circle");

    if matches.opt_present("r") {
        let status = circle.is_switched_on().ok().expect("unable retrieve circle status");
        println!("circle {:016X} relay_status: {}", mac, status);
    } else if matches.opt_present("e") {
        circle.switch_on().ok().expect("unable to switch on circle");
        println!("circle {:016X} switched on", mac);
    } else if matches.opt_present("d") {
        circle.switch_off().ok().expect("unable to switch on circle");
        println!("circle {:016X} switched off", mac);
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();

    opts.optopt("s", "serial", "configure serial-port", "DEVICE")
        .optflag("t", "stub", "configure to use stub implementation")
        .optopt("a", "alias", "assign a alias to Mac", "NAME")
        .optflag("u", "unalias", "forget alias")
        .optflag("l", "list", "list aliassed circles")
        .optflag("r", "relaystatus", "print the relay status of a circle")
        .optflag("e", "enable", "enable the relay of a circle")
        .optflag("d", "disable", "disable the relay of a circle")
        .optflag("p", "powerusage", "print the actual power usage of a circle") // XXX
        .optopt("o", "powersince", "print the total power usage of a given number of days", "DAYS") // XXX
        .optflag("c", "clock", "print the internal clock value of a circle") // XXX
        .optflag("j", "updateclock", "update the internal clock of a circle using Internet time") // XXX
        .optflag("h", "help", "print this help menu")
        .optflagmulti("v", "verbose", "print debug information");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m },
        Err(f) => { panic!(f.to_string()) }
    };

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }

    let mut configfile = env::home_dir().expect("unable to find home/user directory");
    configfile.push(CONFIG);

    let mut config = load_config(&configfile);
    let mut update_config = false;

    if let Some(new_device) = matches.opt_str("s") {
        // client has provided new device; update (any) loaded configuration
        let new_config = update_device_from_config(&config, &new_device);
        config.insert(CONFIG_HEAD.to_string(), toml::Value::Table(new_config));
        update_config = true;
    } else if matches.opt_present("t") {
        // client has indicated to use stub
        let new_config = remove_device_from_config(&config);
        config.insert(CONFIG_HEAD.to_string(), toml::Value::Table(new_config));
        update_config = true;
    }

    let serial = get_device_from_config(&config);
    let aliases = get_aliases(&config);
    let mac;

    if matches.opt_present("l") {
        for (alias, mac) in aliases {
            println!("{} (mac:{:016X})", alias, mac);
        }
        return;
    }

    // at least alias or mac must be specified
    if matches.free.len() == 1 {
        let free = &matches.free[0];
        // find mac by alias or try to decode mac address (16 digit hex)
        mac = aliases.get(free).map_or_else(|| {
            match free.len() {
                16 => u64::from_str_radix(free, 16).ok(),
                _ => None,
            }
        }, |&x| Some(x)).expect("unknown alias or MAC specified");

        //println!("{:?}", mac); // FIXME: remove this
        //println!("{:?}", serial); // FIXME: remove this
        // FIXME: implement more options
        if let Some(new_alias) = matches.opt_str("a") {
            let new_config = update_mac_in_alias(&config, &new_alias, mac);
            config.insert(new_alias, toml::Value::Table(new_config));
            update_config = true;
        } else if matches.opt_present("u") {
            config.remove(free).expect("cannot unalias MAC");
            update_config = true;
        } else {
            plugwise_actions(&matches, serial, mac);
        }
    } else if !update_config {
        panic!("only one alias or MAC must be specified");
    }

    if update_config {
        write_config(&configfile, &config);
    }
}
<commit_msg>circle: add power usage, power buffer, get clock<commit_after>
extern crate getopts;
extern crate time;
extern crate toml;
extern crate plugwise;

use std::env;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path;
use std::collections::HashMap;

use getopts::Options;

use time::Duration;

use plugwise::Device;
use plugwise::ProtocolSnoop;
use plugwise::plugwise;

const CONFIG: &'static str = ".plugwise.toml";
const CONFIG_HEAD: &'static str = "config";
const CONFIG_DEVICE: &'static str = "device";
const ALIAS_MAC: &'static str = "mac";

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options] [mac|alias]", program);
    println!("{}", opts.usage(&brief));
}

fn load_config(configfile: &path::PathBuf) -> toml::Table {
    let mut config = String::new();
    if let Ok(mut file) = File::open(configfile) {
        file.read_to_string(&mut config).ok().expect(
            &format!("unable to read file `{}`", configfile.display()));
    } // errors are silently ignored (assuming file didn't exist)
    toml::Parser::new(&config).parse().expect(&format!("unable to parse `{}`", configfile.display()))
}

fn write_config(configfile: &path::PathBuf, config: &toml::Table) {
    let mut file = File::create(configfile).ok().expect(
        &format!("unable to create `{}`", configfile.display()));
    write!(file, "{}", toml::Value::Table(config.clone())).ok().expect(
        &format!("unable to write to `{}`", configfile.display()));
}

fn get_device_from_config<'a>(config: &'a toml::Table) -> Option<String> {
    config.get(CONFIG_HEAD)
          .map_or(None, |item|item.as_table())
          .map_or(None, |table|table.get(CONFIG_DEVICE))
          .map_or(None, |string|string.as_str())
          .map(|string|string.to_string())
}

fn get_aliases<'a>(config: &'a toml::Table) -> HashMap<String, u64> {
    let mut aliases = HashMap::new();

    for key in config.keys().filter(|&k|k != CONFIG_HEAD) {
        let mac = config.get(key)
                        .map_or(None, |item|item.as_table())
                        .map_or(None, |table|table.get(ALIAS_MAC))
                        .map_or(None, |string|string.as_str());
        if let Some(mac) = mac {
            if mac.len() == 16 {
                let mac = u64::from_str_radix(&mac, 16);
                if let Ok(mac) = mac {
                    aliases.insert(key.to_string(), mac);
                }
            }
        }
    }

    aliases
}

fn update_device_from_config<'a>(config: &'a toml::Table, device: &'a str) -> toml::Table {
    let mut config_table = config.get(CONFIG_HEAD)
                                 .map_or(None, |item|item.as_table())
                                 .map_or(toml::Table::new(), |table|table.clone());
    config_table.insert(CONFIG_DEVICE.to_string(), toml::Value::String(device.to_string()));
    config_table
}

fn remove_device_from_config<'a>(config: &'a toml::Table) -> toml::Table {
    let mut config_table = config.get(CONFIG_HEAD)
                                 .map_or(None, |item|item.as_table())
                                 .map_or(toml::Table::new(), |table|table.clone());
    config_table.remove(CONFIG_DEVICE);
    config_table
}

fn update_mac_in_alias<'a>(config: &'a toml::Table, alias: &'a str, mac: u64) -> toml::Table {
    let mut config_table = config.get(alias)
                                 .map_or(None, |item|item.as_table())
                                 .map_or(toml::Table::new(), |table|table.clone());
    config_table.insert(ALIAS_MAC.to_string(), toml::Value::String(format!("{:016X}", mac)));
    config_table
}

fn plugwise_actions(matches: &getopts::Matches, serial: Option<String>, mac: u64) {
    let mut debug = io::stdout();
    let snoop = match matches.opt_count("v") {
        0 => ProtocolSnoop::Nothing,
        1 => ProtocolSnoop::Debug(&mut debug),
        2 => ProtocolSnoop::Raw(&mut debug),
        _ => ProtocolSnoop::All(&mut debug)
    };
    let device = match serial {
        Some(ref serial) => Device::SerialExt{port: &serial,
                                              timeout: Duration::milliseconds(1000),
                                              retries: 3,
                                              snoop: snoop},
        None => Device::Simulator
    };
    if serial.is_none() {
        println!("WARNING: no serial device is specified to control the Plugwise hardware.");
        println!("         use option -s to specified the TTY/COM device. A simulated");
        println!("         version of the device is now used for testing purposes.");
        println!("");
    }

    let plugwise = plugwise(device).ok().expect("unable to connect to Plugwise device");
    let circle = plugwise.create_circle(mac).ok().expect("unable to connect to circle");

    if matches.opt_present("r") {
        let status = circle.is_switched_on().ok().expect("unable retrieve circle status");
        println!("circle {:016X} relay_status: {}", mac, status);
    } else if matches.opt_present("e") {
        circle.switch_on().ok().expect("unable to switch on circle");
        println!("circle {:016X} switched on", mac);
    } else if matches.opt_present("d") {
        circle.switch_off().ok().expect("unable to switch on circle");
        println!("circle {:016X} switched off", mac);
    } else if matches.opt_present("p") {
        let watts = circle.get_actual_watt_usage().ok()
                                                  .expect("unable to retrieve actual power usage");
        println!("circle {:016X} actual supplied power is: {} W", mac, watts);
    } else if let Some(days) = matches.opt_str("o") {
        let days = u32::from_str_radix(&days, 10).ok()
            .expect("provided number of days must be a positive decimal number");
        let period =  Duration::days(days as i64);
        let entries = Some(period.num_hours() as u32); // power usage entries are stored per hour

        let buffer = circle.get_power_buffer(entries).ok()
            .expect("unable to retrieve power usage history");

        if let Some(last_timestamp) = buffer.keys().last() {
            let kws = buffer.iter()
                            .filter(|&(&k, _)| (*last_timestamp - k) < period)
                            .fold(0.0, |acc, (_, &v)| acc + v);
            println!("circle {:016X} power usage last {} days is: {} kWh", mac, days, kws);
        } else {
            println!("circle {:016X} has no power usage history", mac);
        }
    } else if matches.opt_present("c") {
        let clock = circle.get_clock().ok().expect("unable to retrieve time from circle");
        println!("circle {:016X} time is: {} (UTC)", mac, clock.asctime());
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();

    opts.optopt("s", "serial", "configure serial-port", "DEVICE")
        .optflag("t", "stub", "configure to use stub implementation")
        .optopt("a", "alias", "assign a alias to Mac", "NAME")
        .optflag("u", "unalias", "forget alias")
        .optflag("l", "list", "list aliassed circles")
        .optflag("r", "relaystatus", "print the relay status of a circle")
        .optflag("e", "enable", "enable the relay of a circle")
        .optflag("d", "disable", "disable the relay of a circle")
        .optflag("p", "powerusage", "print the actual power usage of a circle")
        .optopt("o", "powersince", "print the total power usage of a given number of days", "DAYS")
        .optflag("c", "clock", "print the internal clock value of a circle")
        .optflag("j", "updateclock", "update the internal clock of a circle using Internet time") // XXX
        .optflag("h", "help", "print this help menu")
        .optflagmulti("v", "verbose", "print debug information");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m },
        Err(f) => { panic!(f.to_string()) }
    };

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }

    let mut configfile = env::home_dir().expect("unable to find home/user directory");
    configfile.push(CONFIG);

    let mut config = load_config(&configfile);
    let mut update_config = false;

    if let Some(new_device) = matches.opt_str("s") {
        // client has provided new device; update (any) loaded configuration
        let new_config = update_device_from_config(&config, &new_device);
        config.insert(CONFIG_HEAD.to_string(), toml::Value::Table(new_config));
        update_config = true;
    } else if matches.opt_present("t") {
        // client has indicated to use stub
        let new_config = remove_device_from_config(&config);
        config.insert(CONFIG_HEAD.to_string(), toml::Value::Table(new_config));
        update_config = true;
    }

    let serial = get_device_from_config(&config);
    let aliases = get_aliases(&config);
    let mac;

    if matches.opt_present("l") {
        for (alias, mac) in aliases {
            println!("{} (mac:{:016X})", alias, mac);
        }
        return;
    }

    // at least alias or mac must be specified
    if matches.free.len() == 1 {
        let free = &matches.free[0];
        // find mac by alias or try to decode mac address (16 digit hex)
        mac = aliases.get(free).map_or_else(|| {
            match free.len() {
                16 => u64::from_str_radix(free, 16).ok(),
                _ => None,
            }
        }, |&x| Some(x)).expect("unknown alias or MAC specified");

        if let Some(new_alias) = matches.opt_str("a") {
            let new_config = update_mac_in_alias(&config, &new_alias, mac);
            config.insert(new_alias, toml::Value::Table(new_config));
            update_config = true;
        } else if matches.opt_present("u") {
            config.remove(free).expect("cannot unalias MAC");
            update_config = true;
        } else {
            plugwise_actions(&matches, serial, mac);
        }
    } else if !update_config {
        panic!("only one alias or MAC must be specified");
    }

    if update_config {
        write_config(&configfile, &config);
    }
}
<|endoftext|>


<commit_before>#![deny(
    non_camel_case_types,
    non_snake_case,
    path_statements,
    trivial_numeric_casts,
    unstable_features,
    unused_allocation,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_qualifications,
    while_true,
)]

#[macro_use] extern crate log;
extern crate clap;
#[macro_use] extern crate semver;
extern crate toml;
extern crate url;
#[macro_use] extern crate version;

extern crate libimagentrylink;
extern crate libimagrt;
extern crate libimagstore;
extern crate libimagerror;

use std::process::exit;
use std::ops::Deref;

use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup;
use libimagstore::error::StoreError;
use libimagstore::store::Entry;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagerror::trace::trace_error;
use libimagentrylink::external::ExternalLinker;
use clap::ArgMatches;
use url::Url;

mod ui;

use ui::build_ui;

fn main() {
    let rt = generate_runtime_setup("imag-link",
                                    &version!()[..],
                                    "Link entries",
                                    build_ui);

    rt.cli()
        .subcommand_name()
        .map(|name| {
            match name {
                "internal" => handle_internal_linking(&rt),
                "external" => handle_external_linking(&rt),
                _ => {
                    warn!("No commandline call");
                    exit(1);
                },
            }
        });
}

fn handle_internal_linking(rt: &Runtime) {
    use libimagentrylink::internal::InternalLinker;
    use libimagerror::trace::trace_error;

    debug!("Handle internal linking call");
    let cmd = rt.cli().subcommand_matches("internal").unwrap();

    if cmd.is_present("list") {
        debug!("List...");
        for entry in cmd.value_of("list").unwrap().split(',') {
            debug!("Listing for '{}'", entry);
            match get_entry_by_name(rt, entry) {
                Ok(e) => {
                    e.get_internal_links()
                        .map(|links| {
                            for (i, link) in links.iter().map(|l| l.to_str()).filter_map(|x| x).enumerate() {
                                println!("{: <3}: {}", i, link);
                            }
                        })
                        .map_err(|e| trace_error(&e))
                        .ok();
                },

                Err(e) => {
                    trace_error(&e);
                    break;
                },
            }
        }
        debug!("Listing ready!");
    } else {
        let mut from = {
            let from = get_from_entry(&rt);
            if from.is_none() {
                warn!("No 'from' entry");
                exit(1);
            }
            from.unwrap()
        };
        debug!("Link from = {:?}", from.deref());

        let to = {
            let to = get_to_entries(&rt);
            if to.is_none() {
                warn!("No 'to' entry");
                exit(1);
            }
            to.unwrap()
        };
        debug!("Link to = {:?}", to.iter().map(|f| f.deref()).collect::<Vec<&Entry>>());

        match cmd.subcommand_name() {
            Some("add") => {
                for mut to_entry in to {
                    if let Err(e) = to_entry.add_internal_link(&mut from) {
                        trace_error(&e);
                        exit(1);
                    }
                }
            },

            Some("remove") => {
                for mut to_entry in to {
                    if let Err(e) = to_entry.remove_internal_link(&mut from) {
                        trace_error(&e);
                        exit(1);
                    }
                }
            },

            _ => unreachable!(),
        };
    }
}

fn get_from_entry<'a>(rt: &'a Runtime) -> Option<FileLockEntry<'a>> {
    rt.cli()
        .subcommand_matches("internal")
        .unwrap() // safe, we know there is an "internal" subcommand"
        .subcommand_matches("add")
        .unwrap() // safe, we know there is an "add" subcommand
        .value_of("from")
        .and_then(|from_name| {
            match get_entry_by_name(rt, from_name) {
                Err(e) => {
                    debug!("We couldn't get the entry from name: '{:?}'", from_name);
                    trace_error(&e); None
                },
                Ok(e) => Some(e),
            }

        })
}

fn get_to_entries<'a>(rt: &'a Runtime) -> Option<Vec<FileLockEntry<'a>>> {
    rt.cli()
        .subcommand_matches("internal")
        .unwrap() // safe, we know there is an "internal" subcommand"
        .subcommand_matches("add")
        .unwrap() // safe, we know there is an "add" subcommand
        .values_of("to")
        .map(|values| {
            let mut v = vec![];
            for entry in values.map(|v| get_entry_by_name(rt, v)) {
                match entry {
                    Err(e) => trace_error(&e),
                    Ok(e) => v.push(e),
                }
            }
            v
        })
}

fn get_entry_by_name<'a>(rt: &'a Runtime, name: &str) -> Result<FileLockEntry<'a>, StoreError> {
    use libimagstore::storeid::build_entry_path;
    build_entry_path(rt.store(), name)
        .and_then(|path| rt.store().retrieve(path))
}

fn handle_external_linking(rt: &Runtime) {
    use libimagerror::trace::trace_error;

    let scmd       = rt.cli().subcommand_matches("external").unwrap();
    let entry_name = scmd.value_of("id").unwrap(); // enforced by clap
    let entry      = get_entry_by_name(rt, entry_name);
    if entry.is_err() {
        trace_error(&entry.unwrap_err());
        exit(1);
    }
    let mut entry = entry.unwrap();

    if scmd.is_present("add") {
        debug!("Adding link to entry!");
        add_link_to_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("remove") {
        debug!("Removing link from entry!");
        remove_link_from_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("set") {
        debug!("Setting links in entry!");
        set_links_for_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("list") {
        debug!("Listing links in entry!");
        list_links_for_entry(rt.store(), &mut entry);
        return;
    }

    panic!("Clap failed to enforce one of 'add', 'remove', 'set' or 'list'");
}

fn add_link_to_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    let link = matches.value_of("add").unwrap();

    let link = Url::parse(link);
    if link.is_err() {
        debug!("URL parsing error...");
        trace_error(&link.unwrap_err());
        debug!("Exiting");
        exit(1);
    }
    let link = link.unwrap();

    if let Err(e) = entry.add_external_link(store, link) {
        debug!("Error while adding external link...");
        trace_error(&e);
    } else {
        debug!("Everything worked well");
        info!("Ok");
    }
}

fn remove_link_from_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    let link = matches.value_of("remove").unwrap();

    let link = Url::parse(link);
    if link.is_err() {
        trace_error(&link.unwrap_err());
        exit(1);
    }
    let link = link.unwrap();

    if let Err(e) = entry.remove_external_link(store, link) {
        trace_error(&e);
    } else {
        info!("Ok");
    }
}

fn set_links_for_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    let links = matches
        .value_of("links")
        .map(String::from)
        .unwrap()
        .split(',')
        .map(|uri| {
            match Url::parse(uri) {
                Err(e) => {
                    warn!("Could not parse '{}' as URL, ignoring", uri);
                    trace_error(&e);
                    None
                },
                Ok(u) => Some(u),
            }
        })
        .filter_map(|x| x)
        .collect();

    if let Err(e) = entry.set_external_links(store, links) {
        trace_error(&e);
    } else {
        info!("Ok");
    }
}

fn list_links_for_entry(store: &Store, entry: &mut FileLockEntry) {
    let res = entry.get_external_links(store)
        .and_then(|links| {
            for (i, link) in links.iter().enumerate() {
                println!("{: <3}: {}", i, link);
            }
            Ok(())
        });

    match res {
        Err(e) => {
            trace_error(&e);
        },
        Ok(_) => {
            info!("Ok");
        },
    }
}

<commit_msg>Remove unused import<commit_after>#![deny(
    non_camel_case_types,
    non_snake_case,
    path_statements,
    trivial_numeric_casts,
    unstable_features,
    unused_allocation,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_qualifications,
    while_true,
)]

#[macro_use] extern crate log;
extern crate clap;
#[macro_use] extern crate semver;
extern crate toml;
extern crate url;
#[macro_use] extern crate version;

extern crate libimagentrylink;
extern crate libimagrt;
extern crate libimagstore;
extern crate libimagerror;

use std::process::exit;
use std::ops::Deref;

use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup;
use libimagstore::error::StoreError;
use libimagstore::store::Entry;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagerror::trace::trace_error;
use libimagentrylink::external::ExternalLinker;
use clap::ArgMatches;
use url::Url;

mod ui;

use ui::build_ui;

fn main() {
    let rt = generate_runtime_setup("imag-link",
                                    &version!()[..],
                                    "Link entries",
                                    build_ui);

    rt.cli()
        .subcommand_name()
        .map(|name| {
            match name {
                "internal" => handle_internal_linking(&rt),
                "external" => handle_external_linking(&rt),
                _ => {
                    warn!("No commandline call");
                    exit(1);
                },
            }
        });
}

fn handle_internal_linking(rt: &Runtime) {
    use libimagentrylink::internal::InternalLinker;

    debug!("Handle internal linking call");
    let cmd = rt.cli().subcommand_matches("internal").unwrap();

    if cmd.is_present("list") {
        debug!("List...");
        for entry in cmd.value_of("list").unwrap().split(',') {
            debug!("Listing for '{}'", entry);
            match get_entry_by_name(rt, entry) {
                Ok(e) => {
                    e.get_internal_links()
                        .map(|links| {
                            for (i, link) in links.iter().map(|l| l.to_str()).filter_map(|x| x).enumerate() {
                                println!("{: <3}: {}", i, link);
                            }
                        })
                        .map_err(|e| trace_error(&e))
                        .ok();
                },

                Err(e) => {
                    trace_error(&e);
                    break;
                },
            }
        }
        debug!("Listing ready!");
    } else {
        let mut from = {
            let from = get_from_entry(&rt);
            if from.is_none() {
                warn!("No 'from' entry");
                exit(1);
            }
            from.unwrap()
        };
        debug!("Link from = {:?}", from.deref());

        let to = {
            let to = get_to_entries(&rt);
            if to.is_none() {
                warn!("No 'to' entry");
                exit(1);
            }
            to.unwrap()
        };
        debug!("Link to = {:?}", to.iter().map(|f| f.deref()).collect::<Vec<&Entry>>());

        match cmd.subcommand_name() {
            Some("add") => {
                for mut to_entry in to {
                    if let Err(e) = to_entry.add_internal_link(&mut from) {
                        trace_error(&e);
                        exit(1);
                    }
                }
            },

            Some("remove") => {
                for mut to_entry in to {
                    if let Err(e) = to_entry.remove_internal_link(&mut from) {
                        trace_error(&e);
                        exit(1);
                    }
                }
            },

            _ => unreachable!(),
        };
    }
}

fn get_from_entry<'a>(rt: &'a Runtime) -> Option<FileLockEntry<'a>> {
    rt.cli()
        .subcommand_matches("internal")
        .unwrap() // safe, we know there is an "internal" subcommand"
        .subcommand_matches("add")
        .unwrap() // safe, we know there is an "add" subcommand
        .value_of("from")
        .and_then(|from_name| {
            match get_entry_by_name(rt, from_name) {
                Err(e) => {
                    debug!("We couldn't get the entry from name: '{:?}'", from_name);
                    trace_error(&e); None
                },
                Ok(e) => Some(e),
            }

        })
}

fn get_to_entries<'a>(rt: &'a Runtime) -> Option<Vec<FileLockEntry<'a>>> {
    rt.cli()
        .subcommand_matches("internal")
        .unwrap() // safe, we know there is an "internal" subcommand"
        .subcommand_matches("add")
        .unwrap() // safe, we know there is an "add" subcommand
        .values_of("to")
        .map(|values| {
            let mut v = vec![];
            for entry in values.map(|v| get_entry_by_name(rt, v)) {
                match entry {
                    Err(e) => trace_error(&e),
                    Ok(e) => v.push(e),
                }
            }
            v
        })
}

fn get_entry_by_name<'a>(rt: &'a Runtime, name: &str) -> Result<FileLockEntry<'a>, StoreError> {
    use libimagstore::storeid::build_entry_path;
    build_entry_path(rt.store(), name)
        .and_then(|path| rt.store().retrieve(path))
}

fn handle_external_linking(rt: &Runtime) {
    use libimagerror::trace::trace_error;

    let scmd       = rt.cli().subcommand_matches("external").unwrap();
    let entry_name = scmd.value_of("id").unwrap(); // enforced by clap
    let entry      = get_entry_by_name(rt, entry_name);
    if entry.is_err() {
        trace_error(&entry.unwrap_err());
        exit(1);
    }
    let mut entry = entry.unwrap();

    if scmd.is_present("add") {
        debug!("Adding link to entry!");
        add_link_to_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("remove") {
        debug!("Removing link from entry!");
        remove_link_from_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("set") {
        debug!("Setting links in entry!");
        set_links_for_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("list") {
        debug!("Listing links in entry!");
        list_links_for_entry(rt.store(), &mut entry);
        return;
    }

    panic!("Clap failed to enforce one of 'add', 'remove', 'set' or 'list'");
}

fn add_link_to_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    let link = matches.value_of("add").unwrap();

    let link = Url::parse(link);
    if link.is_err() {
        debug!("URL parsing error...");
        trace_error(&link.unwrap_err());
        debug!("Exiting");
        exit(1);
    }
    let link = link.unwrap();

    if let Err(e) = entry.add_external_link(store, link) {
        debug!("Error while adding external link...");
        trace_error(&e);
    } else {
        debug!("Everything worked well");
        info!("Ok");
    }
}

fn remove_link_from_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    let link = matches.value_of("remove").unwrap();

    let link = Url::parse(link);
    if link.is_err() {
        trace_error(&link.unwrap_err());
        exit(1);
    }
    let link = link.unwrap();

    if let Err(e) = entry.remove_external_link(store, link) {
        trace_error(&e);
    } else {
        info!("Ok");
    }
}

fn set_links_for_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    let links = matches
        .value_of("links")
        .map(String::from)
        .unwrap()
        .split(',')
        .map(|uri| {
            match Url::parse(uri) {
                Err(e) => {
                    warn!("Could not parse '{}' as URL, ignoring", uri);
                    trace_error(&e);
                    None
                },
                Ok(u) => Some(u),
            }
        })
        .filter_map(|x| x)
        .collect();

    if let Err(e) = entry.set_external_links(store, links) {
        trace_error(&e);
    } else {
        info!("Ok");
    }
}

fn list_links_for_entry(store: &Store, entry: &mut FileLockEntry) {
    let res = entry.get_external_links(store)
        .and_then(|links| {
            for (i, link) in links.iter().enumerate() {
                println!("{: <3}: {}", i, link);
            }
            Ok(())
        });

    match res {
        Err(e) => {
            trace_error(&e);
        },
        Ok(_) => {
            info!("Ok");
        },
    }
}

<|endoftext|>


<commit_before>#![allow(
    clippy::cognitive_complexity,
    clippy::large_enum_variant,
    clippy::needless_doctest_main
)]
#![warn(
    missing_debug_implementations,
    missing_docs,
    rust_2018_idioms,
    unreachable_pub
)]
#![cfg_attr(docsrs, deny(broken_intra_doc_links))]
#![doc(test(
    no_crate_inject,
    attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
))]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, deny(broken_intra_doc_links))]
#![doc(test(
    no_crate_inject,
    attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
))]

//! Stream utilities for Tokio.
//!
//! A `Stream` is an asynchronous sequence of values. It can be thought of as
//! an asynchronous version of the standard library's `Iterator` trait.
//!
//! This crate provides helpers to work with them. For examples of usage and a more in-depth
//! description of streams you can also refer to the [streams
//! tutorial](https://tokio.rs/tokio/tutorial/streams) on the tokio website.
//!
//! # Iterating over a Stream
//!
//! Due to similarities with the standard library's `Iterator` trait, some new
//! users may assume that they can use `for in` syntax to iterate over a
//! `Stream`, but this is unfortunately not possible. Instead, you can use a
//! `while let` loop as follows:
//!
//! ```rust
//! use tokio_stream::{self as stream, StreamExt};
//!
//! #[tokio::main]
//! async fn main() {
//!     let mut stream = stream::iter(vec![0, 1, 2]);
//!
//!     while let Some(value) = stream.next().await {
//!         println!("Got {}", value);
//!     }
//! }
//! ```
//!
//! # Returning a Stream from a function
//!
//! A common way to stream values from a function is to pass in the sender
//! half of a channel and use the receiver as the stream. This requires awaiting
//! both futures to ensure progress is made. Another alternative is the
//! [async-stream] crate, which contains macros that provide a `yield` keyword
//! and allow you to return an `impl Stream`.
//!
//! [async-stream]: https://docs.rs/async-stream
//!
//! # Conversion to and from AsyncRead/AsyncWrite
//!
//! It is often desirable to convert a `Stream` into an [`AsyncRead`],
//! especially when dealing with plaintext formats streamed over the network.
//! The opposite conversion from an [`AsyncRead`] into a `Stream` is also
//! another commonly required feature. To enable these conversions,
//! [`tokio-util`] provides the [`StreamReader`] and [`ReaderStream`]
//! types when the io feature is enabled.
//!
//! [`tokio-util`]: https://docs.rs/tokio-util/0.4/tokio_util/codec/index.html
//! [`tokio::io`]: https://docs.rs/tokio/1.0/tokio/io/index.html
//! [`AsyncRead`]: https://docs.rs/tokio/1.0/tokio/io/trait.AsyncRead.html
//! [`AsyncWrite`]: https://docs.rs/tokio/1.0/tokio/io/trait.AsyncWrite.html
//! [`ReaderStream`]: https://docs.rs/tokio-util/0.4/tokio_util/io/struct.ReaderStream.html
//! [`StreamReader`]: https://docs.rs/tokio-util/0.4/tokio_util/io/struct.StreamReader.html

#[macro_use]
mod macros;

pub mod wrappers;

mod stream_ext;
pub use stream_ext::{collect::FromStream, StreamExt};

mod empty;
pub use empty::{empty, Empty};

mod iter;
pub use iter::{iter, Iter};

mod once;
pub use once::{once, Once};

mod pending;
pub use pending::{pending, Pending};

mod stream_map;
pub use stream_map::StreamMap;

#[doc(no_inline)]
pub use futures_core::Stream;
<commit_msg>stream: remove duplicate `doc(test(..))` & `cfg_attr` declarations (#3571)<commit_after>#![allow(
    clippy::cognitive_complexity,
    clippy::large_enum_variant,
    clippy::needless_doctest_main
)]
#![warn(
    missing_debug_implementations,
    missing_docs,
    rust_2018_idioms,
    unreachable_pub
)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, deny(broken_intra_doc_links))]
#![doc(test(
    no_crate_inject,
    attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
))]

//! Stream utilities for Tokio.
//!
//! A `Stream` is an asynchronous sequence of values. It can be thought of as
//! an asynchronous version of the standard library's `Iterator` trait.
//!
//! This crate provides helpers to work with them. For examples of usage and a more in-depth
//! description of streams you can also refer to the [streams
//! tutorial](https://tokio.rs/tokio/tutorial/streams) on the tokio website.
//!
//! # Iterating over a Stream
//!
//! Due to similarities with the standard library's `Iterator` trait, some new
//! users may assume that they can use `for in` syntax to iterate over a
//! `Stream`, but this is unfortunately not possible. Instead, you can use a
//! `while let` loop as follows:
//!
//! ```rust
//! use tokio_stream::{self as stream, StreamExt};
//!
//! #[tokio::main]
//! async fn main() {
//!     let mut stream = stream::iter(vec![0, 1, 2]);
//!
//!     while let Some(value) = stream.next().await {
//!         println!("Got {}", value);
//!     }
//! }
//! ```
//!
//! # Returning a Stream from a function
//!
//! A common way to stream values from a function is to pass in the sender
//! half of a channel and use the receiver as the stream. This requires awaiting
//! both futures to ensure progress is made. Another alternative is the
//! [async-stream] crate, which contains macros that provide a `yield` keyword
//! and allow you to return an `impl Stream`.
//!
//! [async-stream]: https://docs.rs/async-stream
//!
//! # Conversion to and from AsyncRead/AsyncWrite
//!
//! It is often desirable to convert a `Stream` into an [`AsyncRead`],
//! especially when dealing with plaintext formats streamed over the network.
//! The opposite conversion from an [`AsyncRead`] into a `Stream` is also
//! another commonly required feature. To enable these conversions,
//! [`tokio-util`] provides the [`StreamReader`] and [`ReaderStream`]
//! types when the io feature is enabled.
//!
//! [`tokio-util`]: https://docs.rs/tokio-util/0.4/tokio_util/codec/index.html
//! [`tokio::io`]: https://docs.rs/tokio/1.0/tokio/io/index.html
//! [`AsyncRead`]: https://docs.rs/tokio/1.0/tokio/io/trait.AsyncRead.html
//! [`AsyncWrite`]: https://docs.rs/tokio/1.0/tokio/io/trait.AsyncWrite.html
//! [`ReaderStream`]: https://docs.rs/tokio-util/0.4/tokio_util/io/struct.ReaderStream.html
//! [`StreamReader`]: https://docs.rs/tokio-util/0.4/tokio_util/io/struct.StreamReader.html

#[macro_use]
mod macros;

pub mod wrappers;

mod stream_ext;
pub use stream_ext::{collect::FromStream, StreamExt};

mod empty;
pub use empty::{empty, Empty};

mod iter;
pub use iter::{iter, Iter};

mod once;
pub use once::{once, Once};

mod pending;
pub use pending::{pending, Pending};

mod stream_map;
pub use stream_map::StreamMap;

#[doc(no_inline)]
pub use futures_core::Stream;
<|endoftext|>


<commit_before>//! Context management
use alloc::boxed::Box;
use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};

pub use self::context::{Context, Status};
pub use self::list::ContextList;
pub use self::switch::switch;

/// Context struct
mod context;

/// Context list
mod list;

/// Context switch function
mod switch;

/// Event handling
pub mod event;

/// File struct - defines a scheme and a file number
pub mod file;

/// Memory struct - contains a set of pages for a context
pub mod memory;

/// Limit on number of contexts
pub const CONTEXT_MAX_CONTEXTS: usize = 65536;

/// Maximum context files
pub const CONTEXT_MAX_FILES: usize = 65536;

/// Contexts list
static CONTEXTS: Once<RwLock<ContextList>> = Once::new();

#[thread_local]
static CONTEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;

pub fn init() {
    let mut contexts = contexts_mut();
    let context_lock = contexts.new_context().expect("could not initialize first context");
    let mut context = context_lock.write();
    let mut fx = unsafe { Box::from_raw(::alloc::heap::allocate(512, 16) as *mut [u8; 512]) };
    for b in fx.iter_mut() {
        *b = 0;
    }

    context.arch.set_fx(fx.as_ptr() as usize);
    context.kfx = Some(fx);
    context.status = Status::Runnable;
    context.running = true;
    context.cpu_id = Some(::cpu_id());
    CONTEXT_ID.store(context.id, Ordering::SeqCst);
}

/// Initialize contexts, called if needed
fn init_contexts() -> RwLock<ContextList> {
    RwLock::new(ContextList::new())
}

/// Get the global schemes list, const
pub fn contexts() -> RwLockReadGuard<'static, ContextList> {
    CONTEXTS.call_once(init_contexts).read()
}

/// Get the global schemes list, mutable
pub fn contexts_mut() -> RwLockWriteGuard<'static, ContextList> {
    CONTEXTS.call_once(init_contexts).write()
}

pub fn context_id() -> usize {
    CONTEXT_ID.load(Ordering::SeqCst)
}
<commit_msg>increase process id range (#729)<commit_after>//! Context management
use alloc::boxed::Box;
use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};

pub use self::context::{Context, Status};
pub use self::list::ContextList;
pub use self::switch::switch;

/// Context struct
mod context;

/// Context list
mod list;

/// Context switch function
mod switch;

/// Event handling
pub mod event;

/// File struct - defines a scheme and a file number
pub mod file;

/// Memory struct - contains a set of pages for a context
pub mod memory;

/// Limit on number of contexts
pub const CONTEXT_MAX_CONTEXTS: usize = usize::max_value() - 1;

/// Maximum context files
pub const CONTEXT_MAX_FILES: usize = 65536;

/// Contexts list
static CONTEXTS: Once<RwLock<ContextList>> = Once::new();

#[thread_local]
static CONTEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;

pub fn init() {
    let mut contexts = contexts_mut();
    let context_lock = contexts.new_context().expect("could not initialize first context");
    let mut context = context_lock.write();
    let mut fx = unsafe { Box::from_raw(::alloc::heap::allocate(512, 16) as *mut [u8; 512]) };
    for b in fx.iter_mut() {
        *b = 0;
    }

    context.arch.set_fx(fx.as_ptr() as usize);
    context.kfx = Some(fx);
    context.status = Status::Runnable;
    context.running = true;
    context.cpu_id = Some(::cpu_id());
    CONTEXT_ID.store(context.id, Ordering::SeqCst);
}

/// Initialize contexts, called if needed
fn init_contexts() -> RwLock<ContextList> {
    RwLock::new(ContextList::new())
}

/// Get the global schemes list, const
pub fn contexts() -> RwLockReadGuard<'static, ContextList> {
    CONTEXTS.call_once(init_contexts).read()
}

/// Get the global schemes list, mutable
pub fn contexts_mut() -> RwLockWriteGuard<'static, ContextList> {
    CONTEXTS.call_once(init_contexts).write()
}

pub fn context_id() -> usize {
    CONTEXT_ID.load(Ordering::SeqCst)
}
<|endoftext|>