// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// 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.

pub mod perm;
pub mod sys;

// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// 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.

pub mod perm;
pub mod sys;

use std::error;
use std::fmt;
use std::marker::PhantomData;
use std::result;
use std::str::FromStr;

use serde;

pub fn deserialize_using_from_str<T, E, D>(d: D) -> result::Result<T, D::Error>
    where T: FromStr<Err = E>,
          E: error::Error,
          D: serde::Deserializer
{
    struct FromStringable<T, E>(PhantomData<T>, PhantomData<E>);

    impl<T, E> serde::de::Visitor for FromStringable<T, E>
        where T: FromStr<Err = E>,
              E: error::Error
    {
        type Value = T;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a string")
        }

        fn visit_str<R>(self, value: &str) -> result::Result<T, R>
            where R: serde::de::Error
        {
            match FromStr::from_str(value) {
                Ok(t) => Ok(t),
                Err(err) => {
                    Err(R::custom(format!("string cannot be parsed: \"{}\" ({})",
                                          value,
                                          err.description())))
                }
            }
        }
    }

    d.deserialize(FromStringable(PhantomData, PhantomData))
}

Implement `Deserialize` for `ServiceSpec` via serde/toml.
[sup] Implement `Deserialize` for `ServiceSpec` via serde/toml.

This change allows a `ServiceSpec` to be created from a TOML string
representation with custom type error checking, validation of
required fields, etc. A future feature will use this implementation to
read a `.toml` file from disk.

The following related changes were made or added:

* Introduce `ServiceBind` which knows how to create itself from a str
(via `FromStr`)
* Implement `Deserialize` for `Topology`
* Implement `Deserialize` for `UpdateStrategy`
* Create a generic `Deserialize` implementation in `core` for types
implementing `FromStr` (used by `UpdateStrategy`, `Topology`,
`ServiceBind`, and indirectly by `PackageIdent`)

Signed-off-by: Fletcher Nichol <77a0fd9e8048bbacd11af4e957bc6ff03b549f49@nichol.ca>
