<commit_before>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::{
    conversion::analysis::fun::{
        function_wrapper::RustConversionType, ArgumentAnalysis, ReceiverMutability,
    },
    types::QualifiedName,
};
use indexmap::set::IndexSet as HashSet;
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use std::borrow::Cow;
use syn::{
    parse_quote, punctuated::Punctuated, token::Comma, FnArg, GenericArgument, PatType, Path,
    PathSegment, ReturnType, Type, TypePath, TypeReference,
};

/// Function which can add explicit lifetime parameters to function signatures
/// where necessary, based on analysis of parameters and return types.
/// This is necessary in three cases:
/// 1) where the parameter is a Pin<&mut T>
///    and the return type is some kind of reference - because lifetime elision
///    is not smart enough to see inside a Pin.
/// 2) as a workaround for https://github.com/dtolnay/cxx/issues/1024, where the
///    input parameter is a non-POD type but the output reference is a POD or
///    built-in type
/// 3) Any parameter is any form of reference, and we're returning an `impl New`
///    3a) an 'impl ValueParam' counts as a reference.
pub(crate) fn add_explicit_lifetime_if_necessary<'r>(
    param_details: &[ArgumentAnalysis],
    mut params: Punctuated<FnArg, Comma>,
    ret_type: Cow<'r, ReturnType>,
    non_pod_types: &HashSet<QualifiedName>,
) -> (
    Option<TokenStream>,
    Punctuated<FnArg, Comma>,
    Cow<'r, ReturnType>,
) {
    log::info!("Beforehand it's {:?}", params.to_token_stream().to_string());
    let has_mutable_receiver = param_details.iter().any(|pd| {
        matches!(pd.self_type, Some((_, ReceiverMutability::Mutable)))
            && !pd.is_placement_return_destination
    });

    let any_param_is_reference = param_details.iter().any(|pd| {
        pd.has_lifetime
            || matches!(
                pd.conversion.rust_conversion,
                RustConversionType::FromValueParamToPtr
            )
    });
    let return_type_is_impl = return_type_is_impl(&ret_type);
    let non_pod_ref_param = reference_parameter_is_non_pod_reference(&params, non_pod_types);
    let ret_type_pod = return_type_is_pod_or_known_type_reference(&ret_type, non_pod_types);
    let returning_impl_with_a_reference_param = return_type_is_impl && any_param_is_reference;
    let hits_1024_bug = non_pod_ref_param && ret_type_pod;
    if !(has_mutable_receiver || hits_1024_bug || returning_impl_with_a_reference_param) {
        return (None, params, ret_type);
    }
    let new_return_type = match ret_type.as_ref() {
        ReturnType::Type(rarrow, boxed_type) => match boxed_type.as_ref() {
            Type::Reference(rtr) => {
                let mut new_rtr = rtr.clone();
                new_rtr.lifetime = Some(parse_quote! { 'a });
                Some(ReturnType::Type(
                    *rarrow,
                    Box::new(Type::Reference(new_rtr)),
                ))
            }
            Type::Path(typ) => {
                let mut new_path = typ.clone();
                add_lifetime_to_pinned_reference(&mut new_path.path.segments)
                    .ok()
                    .map(|_| ReturnType::Type(*rarrow, Box::new(Type::Path(new_path))))
            }
            Type::ImplTrait(tyit) => {
                let old_tyit = tyit.to_token_stream();
                Some(parse_quote! {
                    #rarrow #old_tyit + 'a
                })
            }
            _ => None,
        },
        _ => None,
    };

    match new_return_type {
        None => (None, params, ret_type),
        Some(new_return_type) => {
            for mut param in params.iter_mut() {
                if let FnArg::Typed(PatType { ty, .. }) = &mut param {
                    match ty.as_mut() {
                        Type::Path(TypePath {
                            path: Path { segments, .. },
                            ..
                        }) => add_lifetime_to_pinned_reference(segments).unwrap_or(()),
                        Type::Reference(tyr) => add_lifetime_to_reference(tyr),
                        Type::ImplTrait(tyit) => add_lifetime_to_impl_trait(tyit),
                        _ => {}
                    }
                }
            }

            (Some(quote! { <'a> }), params, Cow::Owned(new_return_type))
        }
    }
}

fn reference_parameter_is_non_pod_reference(
    params: &Punctuated<FnArg, Comma>,
    non_pod_types: &HashSet<QualifiedName>,
) -> bool {
    params.iter().any(|param| match param {
        FnArg::Typed(PatType { ty, .. }) => match ty.as_ref() {
            Type::Reference(TypeReference { elem, .. }) => match elem.as_ref() {
                Type::Path(typ) => {
                    let qn = QualifiedName::from_type_path(typ);
                    non_pod_types.contains(&qn)
                }
                _ => false,
            },
            _ => false,
        },
        _ => false,
    })
}

fn return_type_is_pod_or_known_type_reference(
    ret_type: &ReturnType,
    non_pod_types: &HashSet<QualifiedName>,
) -> bool {
    match ret_type {
        ReturnType::Type(_, boxed_type) => match boxed_type.as_ref() {
            Type::Reference(rtr) => match rtr.elem.as_ref() {
                Type::Path(typ) => {
                    let qn = QualifiedName::from_type_path(typ);
                    !non_pod_types.contains(&qn)
                }
                _ => false,
            },
            _ => false,
        },
        _ => false,
    }
}

fn return_type_is_impl(ret_type: &ReturnType) -> bool {
    matches!(ret_type, ReturnType::Type(_, boxed_type) if matches!(boxed_type.as_ref(), Type::ImplTrait(..)))
}

#[derive(Debug)]
enum AddLifetimeError {
    WasNotPin,
}

fn add_lifetime_to_pinned_reference(
    segments: &mut Punctuated<PathSegment, syn::token::Colon2>,
) -> Result<(), AddLifetimeError> {
    static EXPECTED_SEGMENTS: &[(&str, bool)] = &[
        ("std", false),
        ("pin", false),
        ("Pin", true), // true = act on the arguments of this segment
    ];

    for (seg, (expected_name, act)) in segments.iter_mut().zip(EXPECTED_SEGMENTS.iter()) {
        if seg.ident != expected_name {
            return Err(AddLifetimeError::WasNotPin);
        }
        if *act {
            match &mut seg.arguments {
                syn::PathArguments::AngleBracketed(aba) => match aba.args.iter_mut().next() {
                    Some(GenericArgument::Type(Type::Reference(tyr))) => {
                        add_lifetime_to_reference(tyr);
                    }
                    _ => panic!("Expected generic args with a reference"),
                },
                _ => panic!("Expected angle bracketed args"),
            }
        }
    }
    Ok(())
}

fn add_lifetime_to_reference(tyr: &mut syn::TypeReference) {
    tyr.lifetime = Some(parse_quote! { 'a })
}

fn add_lifetime_to_impl_trait(tyit: &mut syn::TypeImplTrait) {
    tyit.bounds
        .push(syn::TypeParamBound::Lifetime(parse_quote! { 'a }))
}
<commit_msg>Remove extra logging<commit_after>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::{
    conversion::analysis::fun::{
        function_wrapper::RustConversionType, ArgumentAnalysis, ReceiverMutability,
    },
    types::QualifiedName,
};
use indexmap::set::IndexSet as HashSet;
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use std::borrow::Cow;
use syn::{
    parse_quote, punctuated::Punctuated, token::Comma, FnArg, GenericArgument, PatType, Path,
    PathSegment, ReturnType, Type, TypePath, TypeReference,
};

/// Function which can add explicit lifetime parameters to function signatures
/// where necessary, based on analysis of parameters and return types.
/// This is necessary in three cases:
/// 1) where the parameter is a Pin<&mut T>
///    and the return type is some kind of reference - because lifetime elision
///    is not smart enough to see inside a Pin.
/// 2) as a workaround for https://github.com/dtolnay/cxx/issues/1024, where the
///    input parameter is a non-POD type but the output reference is a POD or
///    built-in type
/// 3) Any parameter is any form of reference, and we're returning an `impl New`
///    3a) an 'impl ValueParam' counts as a reference.
pub(crate) fn add_explicit_lifetime_if_necessary<'r>(
    param_details: &[ArgumentAnalysis],
    mut params: Punctuated<FnArg, Comma>,
    ret_type: Cow<'r, ReturnType>,
    non_pod_types: &HashSet<QualifiedName>,
) -> (
    Option<TokenStream>,
    Punctuated<FnArg, Comma>,
    Cow<'r, ReturnType>,
) {
    let has_mutable_receiver = param_details.iter().any(|pd| {
        matches!(pd.self_type, Some((_, ReceiverMutability::Mutable)))
            && !pd.is_placement_return_destination
    });

    let any_param_is_reference = param_details.iter().any(|pd| {
        pd.has_lifetime
            || matches!(
                pd.conversion.rust_conversion,
                RustConversionType::FromValueParamToPtr
            )
    });
    let return_type_is_impl = return_type_is_impl(&ret_type);
    let non_pod_ref_param = reference_parameter_is_non_pod_reference(&params, non_pod_types);
    let ret_type_pod = return_type_is_pod_or_known_type_reference(&ret_type, non_pod_types);
    let returning_impl_with_a_reference_param = return_type_is_impl && any_param_is_reference;
    let hits_1024_bug = non_pod_ref_param && ret_type_pod;
    if !(has_mutable_receiver || hits_1024_bug || returning_impl_with_a_reference_param) {
        return (None, params, ret_type);
    }
    let new_return_type = match ret_type.as_ref() {
        ReturnType::Type(rarrow, boxed_type) => match boxed_type.as_ref() {
            Type::Reference(rtr) => {
                let mut new_rtr = rtr.clone();
                new_rtr.lifetime = Some(parse_quote! { 'a });
                Some(ReturnType::Type(
                    *rarrow,
                    Box::new(Type::Reference(new_rtr)),
                ))
            }
            Type::Path(typ) => {
                let mut new_path = typ.clone();
                add_lifetime_to_pinned_reference(&mut new_path.path.segments)
                    .ok()
                    .map(|_| ReturnType::Type(*rarrow, Box::new(Type::Path(new_path))))
            }
            Type::ImplTrait(tyit) => {
                let old_tyit = tyit.to_token_stream();
                Some(parse_quote! {
                    #rarrow #old_tyit + 'a
                })
            }
            _ => None,
        },
        _ => None,
    };

    match new_return_type {
        None => (None, params, ret_type),
        Some(new_return_type) => {
            for mut param in params.iter_mut() {
                if let FnArg::Typed(PatType { ty, .. }) = &mut param {
                    match ty.as_mut() {
                        Type::Path(TypePath {
                            path: Path { segments, .. },
                            ..
                        }) => add_lifetime_to_pinned_reference(segments).unwrap_or(()),
                        Type::Reference(tyr) => add_lifetime_to_reference(tyr),
                        Type::ImplTrait(tyit) => add_lifetime_to_impl_trait(tyit),
                        _ => {}
                    }
                }
            }

            (Some(quote! { <'a> }), params, Cow::Owned(new_return_type))
        }
    }
}

fn reference_parameter_is_non_pod_reference(
    params: &Punctuated<FnArg, Comma>,
    non_pod_types: &HashSet<QualifiedName>,
) -> bool {
    params.iter().any(|param| match param {
        FnArg::Typed(PatType { ty, .. }) => match ty.as_ref() {
            Type::Reference(TypeReference { elem, .. }) => match elem.as_ref() {
                Type::Path(typ) => {
                    let qn = QualifiedName::from_type_path(typ);
                    non_pod_types.contains(&qn)
                }
                _ => false,
            },
            _ => false,
        },
        _ => false,
    })
}

fn return_type_is_pod_or_known_type_reference(
    ret_type: &ReturnType,
    non_pod_types: &HashSet<QualifiedName>,
) -> bool {
    match ret_type {
        ReturnType::Type(_, boxed_type) => match boxed_type.as_ref() {
            Type::Reference(rtr) => match rtr.elem.as_ref() {
                Type::Path(typ) => {
                    let qn = QualifiedName::from_type_path(typ);
                    !non_pod_types.contains(&qn)
                }
                _ => false,
            },
            _ => false,
        },
        _ => false,
    }
}

fn return_type_is_impl(ret_type: &ReturnType) -> bool {
    matches!(ret_type, ReturnType::Type(_, boxed_type) if matches!(boxed_type.as_ref(), Type::ImplTrait(..)))
}

#[derive(Debug)]
enum AddLifetimeError {
    WasNotPin,
}

fn add_lifetime_to_pinned_reference(
    segments: &mut Punctuated<PathSegment, syn::token::Colon2>,
) -> Result<(), AddLifetimeError> {
    static EXPECTED_SEGMENTS: &[(&str, bool)] = &[
        ("std", false),
        ("pin", false),
        ("Pin", true), // true = act on the arguments of this segment
    ];

    for (seg, (expected_name, act)) in segments.iter_mut().zip(EXPECTED_SEGMENTS.iter()) {
        if seg.ident != expected_name {
            return Err(AddLifetimeError::WasNotPin);
        }
        if *act {
            match &mut seg.arguments {
                syn::PathArguments::AngleBracketed(aba) => match aba.args.iter_mut().next() {
                    Some(GenericArgument::Type(Type::Reference(tyr))) => {
                        add_lifetime_to_reference(tyr);
                    }
                    _ => panic!("Expected generic args with a reference"),
                },
                _ => panic!("Expected angle bracketed args"),
            }
        }
    }
    Ok(())
}

fn add_lifetime_to_reference(tyr: &mut syn::TypeReference) {
    tyr.lifetime = Some(parse_quote! { 'a })
}

fn add_lifetime_to_impl_trait(tyit: &mut syn::TypeImplTrait) {
    tyit.bounds
        .push(syn::TypeParamBound::Lifetime(parse_quote! { 'a }))
}
<|endoftext|>


<commit_before>use std::fs;
use std::io;
use std::path::Path;

#[cfg(unix)]
use tokio::net::UnixListener;
#[cfg(unix)]
use tokio::net::UnixStream;

use futures::Future;

use crate::net::addr::AnySocketAddr;
use crate::net::connect::ToClientStream;
use crate::net::listen::SocketListener;
use crate::net::listen::ToSocketListener;
use crate::net::listen::ToTokioListener;
use crate::net::socket::SocketStream;
use crate::ServerConf;
use std::fmt;
use std::path::PathBuf;
use std::pin::Pin;
use tokio::runtime::Handle;

/// Unix socket address, which is filesystem path.
///
/// Note although this type is available on Windows, unix sockets don't work on Windows.
#[derive(Debug, Clone, PartialEq)]
pub struct SocketAddrUnix(pub(crate) PathBuf);

impl From<PathBuf> for SocketAddrUnix {
    fn from(p: PathBuf) -> Self {
        SocketAddrUnix(p)
    }
}

impl From<&Path> for SocketAddrUnix {
    fn from(p: &Path) -> Self {
        SocketAddrUnix(p.into())
    }
}

impl From<&str> for SocketAddrUnix {
    fn from(p: &str) -> Self {
        SocketAddrUnix(p.into())
    }
}

impl From<&String> for SocketAddrUnix {
    fn from(p: &String) -> Self {
        SocketAddrUnix(p.into())
    }
}

impl From<String> for SocketAddrUnix {
    fn from(p: String) -> Self {
        SocketAddrUnix(p.into())
    }
}

impl fmt::Display for SocketAddrUnix {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0.display(), f)
    }
}

#[cfg(unix)]
impl From<std::os::unix::net::SocketAddr> for SocketAddrUnix {
    fn from(s: std::os::unix::net::SocketAddr) -> Self {
        // can be unnamed
        SocketAddrUnix(s.as_pathname().unwrap_or(Path::new("")).to_owned())
    }
}

#[cfg(unix)]
impl From<tokio::net::unix::SocketAddr> for SocketAddrUnix {
    fn from(s: tokio::net::unix::SocketAddr) -> Self {
        // can be unnamed
        SocketAddrUnix(s.as_pathname().unwrap_or(Path::new("")).to_owned())
    }
}

impl ToSocketListener for SocketAddrUnix {
    #[cfg(unix)]
    fn listen(&self, _conf: &ServerConf) -> io::Result<Box<dyn ToTokioListener + Send>> {
        debug!("binding socket to {}", self);
        Ok(Box::new(::std::os::unix::net::UnixListener::bind(&self.0)?))
    }

    #[cfg(not(unix))]
    fn listen(&self, _conf: &ServerConf) -> io::Result<Box<dyn ToTokioListener + Send>> {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "cannot use unix sockets on non-unix",
        ))
    }

    fn cleanup(&self) {
        if self.0.exists() {
            // TODO: do not panic
            fs::remove_file(&self.0).expect("removing socket during shutdown");
        }
    }
}

#[cfg(unix)]
impl ToTokioListener for ::std::os::unix::net::UnixListener {
    fn into_tokio_listener(self: Box<Self>, handle: &Handle) -> Pin<Box<dyn SocketListener>> {
        let _g = handle.enter();
        Box::pin(UnixListener::from_std(*self).unwrap())
    }

    fn local_addr(&self) -> io::Result<AnySocketAddr> {
        let addr = self.local_addr().unwrap();
        let path = addr.as_pathname().unwrap();
        Ok(AnySocketAddr::Unix(SocketAddrUnix::from(path)))
    }
}

#[cfg(unix)]
impl SocketListener for UnixListener {
    fn accept<'a>(
        self: Pin<&'a mut Self>,
    ) -> Pin<
        Box<
            dyn Future<Output = io::Result<(Pin<Box<dyn SocketStream + Send>>, AnySocketAddr)>>
                + Send
                + 'a,
        >,
    > {
        Box::pin(async move {
            let (socket, peer_addr) = UnixListener::accept(Pin::get_mut(self)).await?;
            Ok((
                Box::pin(socket) as Pin<Box<dyn SocketStream + Send>>,
                AnySocketAddr::Unix(peer_addr.into()),
            ))
        })
    }
}

impl ToClientStream for SocketAddrUnix {
    #[cfg(unix)]
    fn connect(
        &self,
        handle: &Handle,
    ) -> Pin<Box<dyn Future<Output = io::Result<Pin<Box<dyn SocketStream>>>> + Send>> {
        // TODO: async connect
        let stream = match std::os::unix::net::UnixStream::connect(&self.0) {
            Ok(stream) => stream,
            Err(e) => return Box::pin(async { Err(e) }),
        };
        let _g = handle.enter();
        match UnixStream::from_std(stream) {
            Ok(stream) => Box::pin(async { Ok(Box::pin(stream) as Pin<Box<dyn SocketStream>>) }),
            Err(e) => return Box::pin(async { Err(e) }),
        }
    }

    #[cfg(not(unix))]
    fn connect(
        &self,
        _handle: &Handle,
    ) -> Pin<Box<dyn Future<Output = io::Result<Pin<Box<dyn SocketStream>>>> + Send>> {
        use futures::future;
        Box::pin(future::err(io::Error::new(
            io::ErrorKind::Other,
            "cannot use unix sockets on non-unix",
        )))
    }

    fn socket_addr(&self) -> AnySocketAddr {
        AnySocketAddr::Unix(self.clone())
    }
}

#[cfg(unix)]
impl SocketStream for UnixStream {
    fn is_tcp(&self) -> bool {
        false
    }

    fn set_tcp_nodelay(&self, _no_delay: bool) -> io::Result<()> {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "Cannot set nodelay on unix domain socket",
        ))
    }

    fn peer_addr(&self) -> io::Result<AnySocketAddr> {
        Ok(AnySocketAddr::from(UnixStream::peer_addr(self)?))
    }
}

#[cfg(test)]
mod test {
    use crate::net::connect::ToClientStream;
    use crate::net::unix::SocketAddrUnix;
    use crate::AnySocketAddr;
    use std::path::PathBuf;
    use tokio::runtime::Runtime;

    #[cfg(unix)]
    #[test]
    fn peer_addr() {
        let lp = Runtime::new().unwrap();
        let h = lp.handle().clone();

        let dir = tempdir::TempDir::new("peer_addr").unwrap();
        let p = format!("{}/s", dir.path().display());
        let _server = std::os::unix::net::UnixListener::bind(&p).unwrap();

        let client =
            lp.block_on(async { SocketAddrUnix(PathBuf::from(&p)).connect(&h).await.unwrap() });

        assert_eq!(
            AnySocketAddr::Unix(SocketAddrUnix::from(&p)),
            client.peer_addr().unwrap()
        );
    }
}
<commit_msg>Make unix sockets non-blocking too<commit_after>use std::fs;
use std::io;
use std::path::Path;

#[cfg(unix)]
use tokio::net::UnixListener;
#[cfg(unix)]
use tokio::net::UnixStream;

use futures::Future;

use crate::net::addr::AnySocketAddr;
use crate::net::connect::ToClientStream;
use crate::net::listen::SocketListener;
use crate::net::listen::ToSocketListener;
use crate::net::listen::ToTokioListener;
use crate::net::socket::SocketStream;
use crate::ServerConf;
use std::fmt;
use std::path::PathBuf;
use std::pin::Pin;
use tokio::runtime::Handle;

/// Unix socket address, which is filesystem path.
///
/// Note although this type is available on Windows, unix sockets don't work on Windows.
#[derive(Debug, Clone, PartialEq)]
pub struct SocketAddrUnix(pub(crate) PathBuf);

impl From<PathBuf> for SocketAddrUnix {
    fn from(p: PathBuf) -> Self {
        SocketAddrUnix(p)
    }
}

impl From<&Path> for SocketAddrUnix {
    fn from(p: &Path) -> Self {
        SocketAddrUnix(p.into())
    }
}

impl From<&str> for SocketAddrUnix {
    fn from(p: &str) -> Self {
        SocketAddrUnix(p.into())
    }
}

impl From<&String> for SocketAddrUnix {
    fn from(p: &String) -> Self {
        SocketAddrUnix(p.into())
    }
}

impl From<String> for SocketAddrUnix {
    fn from(p: String) -> Self {
        SocketAddrUnix(p.into())
    }
}

impl fmt::Display for SocketAddrUnix {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0.display(), f)
    }
}

#[cfg(unix)]
impl From<std::os::unix::net::SocketAddr> for SocketAddrUnix {
    fn from(s: std::os::unix::net::SocketAddr) -> Self {
        // can be unnamed
        SocketAddrUnix(s.as_pathname().unwrap_or(Path::new("")).to_owned())
    }
}

#[cfg(unix)]
impl From<tokio::net::unix::SocketAddr> for SocketAddrUnix {
    fn from(s: tokio::net::unix::SocketAddr) -> Self {
        // can be unnamed
        SocketAddrUnix(s.as_pathname().unwrap_or(Path::new("")).to_owned())
    }
}

impl ToSocketListener for SocketAddrUnix {
    #[cfg(unix)]
    fn listen(&self, _conf: &ServerConf) -> io::Result<Box<dyn ToTokioListener + Send>> {
        debug!("binding socket to {}", self);
        Ok(Box::new(::std::os::unix::net::UnixListener::bind(&self.0)?))
    }

    #[cfg(not(unix))]
    fn listen(&self, _conf: &ServerConf) -> io::Result<Box<dyn ToTokioListener + Send>> {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "cannot use unix sockets on non-unix",
        ))
    }

    fn cleanup(&self) {
        if self.0.exists() {
            // TODO: do not panic
            fs::remove_file(&self.0).expect("removing socket during shutdown");
        }
    }
}

#[cfg(unix)]
impl ToTokioListener for ::std::os::unix::net::UnixListener {
    fn into_tokio_listener(self: Box<Self>, handle: &Handle) -> Pin<Box<dyn SocketListener>> {
        let _g = handle.enter();
        self.set_nonblocking(true).unwrap();
        Box::pin(UnixListener::from_std(*self).unwrap())
    }

    fn local_addr(&self) -> io::Result<AnySocketAddr> {
        let addr = self.local_addr().unwrap();
        let path = addr.as_pathname().unwrap();
        Ok(AnySocketAddr::Unix(SocketAddrUnix::from(path)))
    }
}

#[cfg(unix)]
impl SocketListener for UnixListener {
    fn accept<'a>(
        self: Pin<&'a mut Self>,
    ) -> Pin<
        Box<
            dyn Future<Output = io::Result<(Pin<Box<dyn SocketStream + Send>>, AnySocketAddr)>>
                + Send
                + 'a,
        >,
    > {
        Box::pin(async move {
            let (socket, peer_addr) = UnixListener::accept(Pin::get_mut(self)).await?;
            Ok((
                Box::pin(socket) as Pin<Box<dyn SocketStream + Send>>,
                AnySocketAddr::Unix(peer_addr.into()),
            ))
        })
    }
}

impl ToClientStream for SocketAddrUnix {
    #[cfg(unix)]
    fn connect(
        &self,
        handle: &Handle,
    ) -> Pin<Box<dyn Future<Output = io::Result<Pin<Box<dyn SocketStream>>>> + Send>> {
        // TODO: async connect
        let stream = match std::os::unix::net::UnixStream::connect(&self.0) {
            Ok(stream) => stream,
            Err(e) => return Box::pin(async { Err(e) }),
        };
        let _g = handle.enter();
        stream.set_nonblocking(true).unwrap();
        match UnixStream::from_std(stream) {
            Ok(stream) => Box::pin(async { Ok(Box::pin(stream) as Pin<Box<dyn SocketStream>>) }),
            Err(e) => return Box::pin(async { Err(e) }),
        }
    }

    #[cfg(not(unix))]
    fn connect(
        &self,
        _handle: &Handle,
    ) -> Pin<Box<dyn Future<Output = io::Result<Pin<Box<dyn SocketStream>>>> + Send>> {
        use futures::future;
        Box::pin(future::err(io::Error::new(
            io::ErrorKind::Other,
            "cannot use unix sockets on non-unix",
        )))
    }

    fn socket_addr(&self) -> AnySocketAddr {
        AnySocketAddr::Unix(self.clone())
    }
}

#[cfg(unix)]
impl SocketStream for UnixStream {
    fn is_tcp(&self) -> bool {
        false
    }

    fn set_tcp_nodelay(&self, _no_delay: bool) -> io::Result<()> {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "Cannot set nodelay on unix domain socket",
        ))
    }

    fn peer_addr(&self) -> io::Result<AnySocketAddr> {
        Ok(AnySocketAddr::from(UnixStream::peer_addr(self)?))
    }
}

#[cfg(test)]
mod test {
    use crate::net::connect::ToClientStream;
    use crate::net::unix::SocketAddrUnix;
    use crate::AnySocketAddr;
    use std::path::PathBuf;
    use tokio::runtime::Runtime;

    #[cfg(unix)]
    #[test]
    fn peer_addr() {
        let lp = Runtime::new().unwrap();
        let h = lp.handle().clone();

        let dir = tempdir::TempDir::new("peer_addr").unwrap();
        let p = format!("{}/s", dir.path().display());
        let _server = std::os::unix::net::UnixListener::bind(&p).unwrap();

        let client =
            lp.block_on(async { SocketAddrUnix(PathBuf::from(&p)).connect(&h).await.unwrap() });

        assert_eq!(
            AnySocketAddr::Unix(SocketAddrUnix::from(&p)),
            client.peer_addr().unwrap()
        );
    }
}
<|endoftext|>


<commit_before><commit_msg>add push method<commit_after><|endoftext|>


<commit_before><commit_msg>Rustfmt<commit_after><|endoftext|>


<commit_before><commit_msg>Added InvalidLinktype error for get_description and get_name, changed some error strings.<commit_after><|endoftext|>


<commit_before><commit_msg>small doc fixes<commit_after><|endoftext|>


<commit_before><commit_msg>Add FIXME.<commit_after><|endoftext|>


<commit_before><commit_msg>Verbose argument names<commit_after><|endoftext|>


<commit_before><commit_msg>Add some module docs<commit_after><|endoftext|>


<commit_before>static STILL: u8 = 0;
static NORTH: u8 = 1;
static EAST: u8 = 2;
static SOUTH: u8 = 3;
static WEST: u8 = 4;

static DIRECTIONS: [u8; 5] = [STILL, NORTH, EAST, SOUTH, WEST];
static CARDINALS: [u8; 4] = [NORTH, EAST, SOUTH, WEST];

namespace hlt{
	struct Location{
		unsigned short x, y;
	};
	static bool operator<(const Location& l1, const Location& l2) {
		return ((l1.x + l1.y)*((unsigned int)l1.x + l1.y + 1) / 2) + l1.y < ((l2.x + l2.y)*((unsigned int)l2.x + l2.y + 1) / 2) + l2.y;
	}

	struct Site{
		unsigned char owner;
		unsigned char strength;
		unsigned char production;
	};

	class GameMap{
	public:
		std::vector< std::vector<Site> > contents;
		unsigned short width, height; //Number of rows & columns, NOT maximum index.

		GameMap() {
			width = 0;
			height = 0;
			contents = std::vector< std::vector<Site> >(height, std::vector<Site>(width, { 0, 0, 0 }));
		}
		GameMap(const GameMap &otherMap) {
			width = otherMap.width;
			height = otherMap.height;
			contents = otherMap.contents;
		}
		GameMap(int width, int height) {
			width = width;
			height = height;
			contents = std::vector< std::vector<Site> >(height, std::vector<Site>(width, { 0, 0, 0 }));
		}

		bool inBounds(Location l) {
			return l.x < width && l.y < height;
		}
		float getDistance(Location l1, Location l2) {
			short dx = abs(l1.x - l2.x), dy = abs(l1.y - l2.y);
			if(dx > width / 2) dx = width - dx;
			if(dy > height / 2) dy = height - dy;
			return dx + dy;
		}
		float getAngle(Location l1, Location l2) {
			short dx = l2.x - l1.x, dy = l2.y - l1.y;
			if(dx > width - dx) dx -= width;
			else if(-dx > width + dx) dx += width;
			if(dy > height - dy) dy -= height;
			else if(-dy > height + dy) dy += height;
			return atan2(dy, dx);
		}

		Location getLocation(Location l, unsigned char direction) {
			if(direction != STILL) {
				if(direction == NORTH) {
					if(l.y == 0) l.y = height - 1;
					else l.y--;
				}
				else if(direction == EAST) {
					if(l.x == width - 1) l.x = 0;
					else l.x++;
				}
				else if(direction == SOUTH) {
					if(l.y == height - 1) l.y = 0;
					else l.y++;
				}
				else if(direction == WEST) {
					if(l.x == 0) l.x = width - 1;
					else l.x--;
				}
			}
			return l;
		}
		Site& getSite(Location l, unsigned char direction = STILL) {
			l = getLocation(l, direction);
			return contents[l.y][l.x];
		}
	};

	struct Move{
		Location loc; unsigned char dir;
	};
	static bool operator<(const Move& m1, const Move& m2) {
		unsigned int l1Prod = ((m1.loc.x + m1.loc.y)*((unsigned int)m1.loc.x + m1.loc.y + 1) / 2) + m1.loc.y, l2Prod = ((m2.loc.x + m2.loc.y)*((unsigned int)m2.loc.x + m2.loc.y + 1) / 2) + m2.loc.y;
		return ((l1Prod + m1.dir)*(l1Prod + m1.dir + 1) / 2) + m1.dir < ((l2Prod + m2.dir)*(l2Prod + m2.dir + 1) / 2) + m2.dir;
	}
}

#endif
<commit_msg>Added more Rust<commit_after>use std::hash;
use std::cmp;

static STILL: u8 = 0;
static NORTH: u8 = 1;
static EAST: u8 = 2;
static SOUTH: u8 = 3;
static WEST: u8 = 4;

static DIRECTIONS: [u8; 5] = [STILL, NORTH, EAST, SOUTH, WEST];
static CARDINALS: [u8; 4] = [NORTH, EAST, SOUTH, WEST];

#[derive(Copy, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, Debug)]
struct Location{
	x: u16,
	y; u16,
};

#[derive(Copy, Clone, Eq, Debug)]
struct Site {
	owner: u8;
	strength: u8;
	production: u8;
};

#[derive(Copy, Clone, Debug)]
struct GameMap {
	contents: Vec< Vec<Site> >;
	width: u16, //Number of columns.
	height: u16, //Number of rows.
}

trait GameMapUtils {
	fn inBounds(&self) -> bool;
	fn getDistance(&self, l1: Location, l2: Location) -> u16;
	fn getAngle(&self, l1: Location, l2: Location) -> f64;
	fn getLocation(&self, l: Location, d: u8) -> Location;
	fn getSite(&mut self)
}

	GameMap() {
		width = 0;
		height = 0;
		contents = std::vector< std::vector<Site> >(height, std::vector<Site>(width, { 0, 0, 0 }));
	}
	GameMap(const GameMap &otherMap) {
		width = otherMap.width;
		height = otherMap.height;
		contents = otherMap.contents;
	}
	GameMap(int width, int height) {
		width = width;
		height = height;
		contents = std::vector< std::vector<Site> >(height, std::vector<Site>(width, { 0, 0, 0 }));
	}

	bool inBounds(Location l) {
		return l.x < width && l.y < height;
	}
	float getDistance(Location l1, Location l2) {
		short dx = abs(l1.x - l2.x), dy = abs(l1.y - l2.y);
		if(dx > width / 2) dx = width - dx;
		if(dy > height / 2) dy = height - dy;
		return dx + dy;
	}
	float getAngle(Location l1, Location l2) {
		short dx = l2.x - l1.x, dy = l2.y - l1.y;
		if(dx > width - dx) dx -= width;
		else if(-dx > width + dx) dx += width;
		if(dy > height - dy) dy -= height;
		else if(-dy > height + dy) dy += height;
		return atan2(dy, dx);
	}

	Location getLocation(Location l, unsigned char direction) {
		if(direction != STILL) {
			if(direction == NORTH) {
				if(l.y == 0) l.y = height - 1;
				else l.y--;
			}
			else if(direction == EAST) {
				if(l.x == width - 1) l.x = 0;
				else l.x++;
			}
			else if(direction == SOUTH) {
				if(l.y == height - 1) l.y = 0;
				else l.y++;
			}
			else if(direction == WEST) {
				if(l.x == 0) l.x = width - 1;
				else l.x--;
			}
		}
		return l;
	}
	Site& getSite(Location l, unsigned char direction = STILL) {
		l = getLocation(l, direction);
		return contents[l.y][l.x];
	}
};

struct Move{
	Location loc; unsigned char dir;
};
static bool operator<(const Move& m1, const Move& m2) {
	unsigned int l1Prod = ((m1.loc.x + m1.loc.y)*((unsigned int)m1.loc.x + m1.loc.y + 1) / 2) + m1.loc.y, l2Prod = ((m2.loc.x + m2.loc.y)*((unsigned int)m2.loc.x + m2.loc.y + 1) / 2) + m2.loc.y;
	return ((l1Prod + m1.dir)*(l1Prod + m1.dir + 1) / 2) + m1.dir < ((l2Prod + m2.dir)*(l2Prod + m2.dir + 1) / 2) + m2.dir;
}<|endoftext|>


<commit_before>//! Contains basic data about various HIR declarations.

use std::sync::Arc;

use hir_expand::{
    hygiene::Hygiene,
    name::{name, AsName, Name},
    AstId, InFile,
};
use ra_prof::profile;
use ra_syntax::ast::{
    self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner, VisibilityOwner,
};

use crate::{
    attr::Attrs,
    db::DefDatabase,
    path::{path, GenericArgs, Path},
    src::HasSource,
    type_ref::{Mutability, TypeBound, TypeRef},
    visibility::RawVisibility,
    AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule,
    ImplId, Intern, Lookup, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FunctionData {
    pub name: Name,
    pub params: Vec<TypeRef>,
    pub ret_type: TypeRef,
    pub attrs: Attrs,
    /// True if the first param is `self`. This is relevant to decide whether this
    /// can be called as a method.
    pub has_self_param: bool,
    pub visibility: RawVisibility,
}

impl FunctionData {
    pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> {
        let loc = func.lookup(db);
        let src = loc.source(db);
        let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing);
        let mut params = Vec::new();
        let mut has_self_param = false;
        if let Some(param_list) = src.value.param_list() {
            if let Some(self_param) = param_list.self_param() {
                let self_type = if let Some(type_ref) = self_param.ascribed_type() {
                    TypeRef::from_ast(type_ref)
                } else {
                    let self_type = TypeRef::Path(name![Self].into());
                    match self_param.kind() {
                        ast::SelfParamKind::Owned => self_type,
                        ast::SelfParamKind::Ref => {
                            TypeRef::Reference(Box::new(self_type), Mutability::Shared)
                        }
                        ast::SelfParamKind::MutRef => {
                            TypeRef::Reference(Box::new(self_type), Mutability::Mut)
                        }
                    }
                };
                params.push(self_type);
                has_self_param = true;
            }
            for param in param_list.params() {
                let type_ref = TypeRef::from_ast_opt(param.ascribed_type());
                params.push(type_ref);
            }
        }
        let attrs = Attrs::new(&src.value, &Hygiene::new(db.upcast(), src.file_id));

        let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) {
            TypeRef::from_ast(type_ref)
        } else {
            TypeRef::unit()
        };

        let ret_type = if src.value.async_token().is_some() {
            let future_impl = desugar_future_path(ret_type);
            let ty_bound = TypeBound::Path(future_impl);
            TypeRef::ImplTrait(vec![ty_bound])
        } else {
            ret_type
        };

        let vis_default = RawVisibility::default_for_container(loc.container);
        let visibility =
            RawVisibility::from_ast_with_default(db, vis_default, src.map(|s| s.visibility()));

        let sig = FunctionData { name, params, ret_type, has_self_param, visibility, attrs };
        Arc::new(sig)
    }
}

fn desugar_future_path(orig: TypeRef) -> Path {
    let path = path![std::future::Future];
    let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect();
    let mut last = GenericArgs::empty();
    last.bindings.push((name![Output], orig));
    generic_args.push(Some(Arc::new(last)));

    Path::from_known_path(path, generic_args)
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypeAliasData {
    pub name: Name,
    pub type_ref: Option<TypeRef>,
    pub visibility: RawVisibility,
}

impl TypeAliasData {
    pub(crate) fn type_alias_data_query(
        db: &dyn DefDatabase,
        typ: TypeAliasId,
    ) -> Arc<TypeAliasData> {
        let loc = typ.lookup(db);
        let node = loc.source(db);
        let name = node.value.name().map_or_else(Name::missing, |n| n.as_name());
        let type_ref = node.value.type_ref().map(TypeRef::from_ast);
        let vis_default = RawVisibility::default_for_container(loc.container);
        let visibility =
            RawVisibility::from_ast_with_default(db, vis_default, node.map(|n| n.visibility()));
        Arc::new(TypeAliasData { name, type_ref, visibility })
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TraitData {
    pub name: Name,
    pub items: Vec<(Name, AssocItemId)>,
    pub auto: bool,
}

impl TraitData {
    pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> {
        let src = tr.lookup(db).source(db);
        let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
        let auto = src.value.auto_token().is_some();
        let ast_id_map = db.ast_id_map(src.file_id);

        let container = AssocContainerId::TraitId(tr);
        let items = if let Some(item_list) = src.value.item_list() {
            item_list
                .impl_items()
                .map(|item_node| match item_node {
                    ast::ImplItem::FnDef(it) => {
                        let name = it.name().map_or_else(Name::missing, |it| it.as_name());
                        let def = FunctionLoc {
                            container,
                            ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)),
                        }
                        .intern(db)
                        .into();
                        (name, def)
                    }
                    ast::ImplItem::ConstDef(it) => {
                        let name = it.name().map_or_else(Name::missing, |it| it.as_name());
                        let def = ConstLoc {
                            container,
                            ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)),
                        }
                        .intern(db)
                        .into();
                        (name, def)
                    }
                    ast::ImplItem::TypeAliasDef(it) => {
                        let name = it.name().map_or_else(Name::missing, |it| it.as_name());
                        let def = TypeAliasLoc {
                            container,
                            ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)),
                        }
                        .intern(db)
                        .into();
                        (name, def)
                    }
                })
                .collect()
        } else {
            Vec::new()
        };
        Arc::new(TraitData { name, items, auto })
    }

    pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
        self.items.iter().filter_map(|(_name, item)| match item {
            AssocItemId::TypeAliasId(t) => Some(*t),
            _ => None,
        })
    }

    pub fn associated_type_by_name(&self, name: &Name) -> Option<TypeAliasId> {
        self.items.iter().find_map(|(item_name, item)| match item {
            AssocItemId::TypeAliasId(t) if item_name == name => Some(*t),
            _ => None,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ImplData {
    pub target_trait: Option<TypeRef>,
    pub target_type: TypeRef,
    pub items: Vec<AssocItemId>,
    pub is_negative: bool,
}

impl ImplData {
    pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> {
        let _p = profile("impl_data_query");
        let impl_loc = id.lookup(db);
        let src = impl_loc.source(db);

        let target_trait = src.value.target_trait().map(TypeRef::from_ast);
        let target_type = TypeRef::from_ast_opt(src.value.target_type());
        let is_negative = src.value.excl_token().is_some();
        let module_id = impl_loc.container.module(db);

        let mut items = Vec::new();

        if let Some(item_list) = src.value.item_list() {
            let mut expander = Expander::new(db, impl_loc.ast_id.file_id, module_id);
            items.extend(collect_impl_items(db, item_list.impl_items(), src.file_id, id));
            items.extend(collect_impl_items_in_macros(
                db,
                &mut expander,
                &src.with_value(item_list),
                id,
            ));
        }

        let res = ImplData { target_trait, target_type, items, is_negative };
        Arc::new(res)
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ConstData {
    /// const _: () = ();
    pub name: Option<Name>,
    pub type_ref: TypeRef,
    pub visibility: RawVisibility,
}

impl ConstData {
    pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> {
        let loc = konst.lookup(db);
        let node = loc.source(db);
        let vis_default = RawVisibility::default_for_container(loc.container);
        Arc::new(ConstData::new(db, vis_default, node))
    }

    pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<ConstData> {
        let node = konst.lookup(db).source(db);
        Arc::new(ConstData::new(db, RawVisibility::private(), node))
    }

    fn new<N: NameOwner + TypeAscriptionOwner + VisibilityOwner>(
        db: &dyn DefDatabase,
        vis_default: RawVisibility,
        node: InFile<N>,
    ) -> ConstData {
        let name = node.value.name().map(|n| n.as_name());
        let type_ref = TypeRef::from_ast_opt(node.value.ascribed_type());
        let visibility =
            RawVisibility::from_ast_with_default(db, vis_default, node.map(|n| n.visibility()));
        ConstData { name, type_ref, visibility }
    }
}

fn collect_impl_items_in_macros(
    db: &dyn DefDatabase,
    expander: &mut Expander,
    impl_def: &InFile<ast::ItemList>,
    id: ImplId,
) -> Vec<AssocItemId> {
    let mut res = Vec::new();

    // We set a limit to protect against infinite recursion
    let limit = 100;

    for m in impl_def.value.syntax().children().filter_map(ast::MacroCall::cast) {
        res.extend(collect_impl_items_in_macro(db, expander, m, id, limit))
    }

    res
}

fn collect_impl_items_in_macro(
    db: &dyn DefDatabase,
    expander: &mut Expander,
    m: ast::MacroCall,
    id: ImplId,
    limit: usize,
) -> Vec<AssocItemId> {
    if limit == 0 {
        return Vec::new();
    }

    if let Some((mark, items)) = expander.enter_expand(db, None, m) {
        let items: InFile<ast::MacroItems> = expander.to_source(items);
        let mut res = collect_impl_items(
            db,
            items.value.items().filter_map(|it| ImplItem::cast(it.syntax().clone())),
            items.file_id,
            id,
        );
        // Recursive collect macros
        // Note that ast::ModuleItem do not include ast::MacroCall
        // We cannot use ModuleItemOwner::items here
        for it in items.value.syntax().children().filter_map(ast::MacroCall::cast) {
            res.extend(collect_impl_items_in_macro(db, expander, it, id, limit - 1))
        }
        expander.exit(db, mark);
        res
    } else {
        Vec::new()
    }
}

fn collect_impl_items(
    db: &dyn DefDatabase,
    impl_items: impl Iterator<Item = ImplItem>,
    file_id: crate::HirFileId,
    id: ImplId,
) -> Vec<AssocItemId> {
    let items = db.ast_id_map(file_id);
    let crate_graph = db.crate_graph();
    let module_id = id.lookup(db).container.module(db);

    impl_items
        .filter_map(|item_node| match item_node {
            ast::ImplItem::FnDef(it) => {
                let def = FunctionLoc {
                    container: AssocContainerId::ImplId(id),
                    ast_id: AstId::new(file_id, items.ast_id(&it)),
                }
                .intern(db);

                if !db
                    .function_data(def)
                    .attrs
                    .is_cfg_enabled(&crate_graph[module_id.krate].cfg_options)
                {
                    None
                } else {
                    Some(def.into())
                }
            }
            ast::ImplItem::ConstDef(it) => {
                let def = ConstLoc {
                    container: AssocContainerId::ImplId(id),
                    ast_id: AstId::new(file_id, items.ast_id(&it)),
                }
                .intern(db);
                Some(def.into())
            }
            ast::ImplItem::TypeAliasDef(it) => {
                let def = TypeAliasLoc {
                    container: AssocContainerId::ImplId(id),
                    ast_id: AstId::new(file_id, items.ast_id(&it)),
                }
                .intern(db);
                Some(def.into())
            }
        })
        .collect()
}
<commit_msg>Use Expander for cfg handling in impls<commit_after>//! Contains basic data about various HIR declarations.

use std::sync::Arc;

use hir_expand::{
    hygiene::Hygiene,
    name::{name, AsName, Name},
    AstId, InFile,
};
use ra_prof::profile;
use ra_syntax::ast::{
    self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner, VisibilityOwner,
};

use crate::{
    attr::Attrs,
    db::DefDatabase,
    path::{path, GenericArgs, Path},
    src::HasSource,
    type_ref::{Mutability, TypeBound, TypeRef},
    visibility::RawVisibility,
    AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule,
    ImplId, Intern, Lookup, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FunctionData {
    pub name: Name,
    pub params: Vec<TypeRef>,
    pub ret_type: TypeRef,
    pub attrs: Attrs,
    /// True if the first param is `self`. This is relevant to decide whether this
    /// can be called as a method.
    pub has_self_param: bool,
    pub visibility: RawVisibility,
}

impl FunctionData {
    pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> {
        let loc = func.lookup(db);
        let src = loc.source(db);
        let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing);
        let mut params = Vec::new();
        let mut has_self_param = false;
        if let Some(param_list) = src.value.param_list() {
            if let Some(self_param) = param_list.self_param() {
                let self_type = if let Some(type_ref) = self_param.ascribed_type() {
                    TypeRef::from_ast(type_ref)
                } else {
                    let self_type = TypeRef::Path(name![Self].into());
                    match self_param.kind() {
                        ast::SelfParamKind::Owned => self_type,
                        ast::SelfParamKind::Ref => {
                            TypeRef::Reference(Box::new(self_type), Mutability::Shared)
                        }
                        ast::SelfParamKind::MutRef => {
                            TypeRef::Reference(Box::new(self_type), Mutability::Mut)
                        }
                    }
                };
                params.push(self_type);
                has_self_param = true;
            }
            for param in param_list.params() {
                let type_ref = TypeRef::from_ast_opt(param.ascribed_type());
                params.push(type_ref);
            }
        }
        let attrs = Attrs::new(&src.value, &Hygiene::new(db.upcast(), src.file_id));

        let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) {
            TypeRef::from_ast(type_ref)
        } else {
            TypeRef::unit()
        };

        let ret_type = if src.value.async_token().is_some() {
            let future_impl = desugar_future_path(ret_type);
            let ty_bound = TypeBound::Path(future_impl);
            TypeRef::ImplTrait(vec![ty_bound])
        } else {
            ret_type
        };

        let vis_default = RawVisibility::default_for_container(loc.container);
        let visibility =
            RawVisibility::from_ast_with_default(db, vis_default, src.map(|s| s.visibility()));

        let sig = FunctionData { name, params, ret_type, has_self_param, visibility, attrs };
        Arc::new(sig)
    }
}

fn desugar_future_path(orig: TypeRef) -> Path {
    let path = path![std::future::Future];
    let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect();
    let mut last = GenericArgs::empty();
    last.bindings.push((name![Output], orig));
    generic_args.push(Some(Arc::new(last)));

    Path::from_known_path(path, generic_args)
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypeAliasData {
    pub name: Name,
    pub type_ref: Option<TypeRef>,
    pub visibility: RawVisibility,
}

impl TypeAliasData {
    pub(crate) fn type_alias_data_query(
        db: &dyn DefDatabase,
        typ: TypeAliasId,
    ) -> Arc<TypeAliasData> {
        let loc = typ.lookup(db);
        let node = loc.source(db);
        let name = node.value.name().map_or_else(Name::missing, |n| n.as_name());
        let type_ref = node.value.type_ref().map(TypeRef::from_ast);
        let vis_default = RawVisibility::default_for_container(loc.container);
        let visibility =
            RawVisibility::from_ast_with_default(db, vis_default, node.map(|n| n.visibility()));
        Arc::new(TypeAliasData { name, type_ref, visibility })
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TraitData {
    pub name: Name,
    pub items: Vec<(Name, AssocItemId)>,
    pub auto: bool,
}

impl TraitData {
    pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> {
        let src = tr.lookup(db).source(db);
        let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
        let auto = src.value.auto_token().is_some();
        let ast_id_map = db.ast_id_map(src.file_id);

        let container = AssocContainerId::TraitId(tr);
        let items = if let Some(item_list) = src.value.item_list() {
            item_list
                .impl_items()
                .map(|item_node| match item_node {
                    ast::ImplItem::FnDef(it) => {
                        let name = it.name().map_or_else(Name::missing, |it| it.as_name());
                        let def = FunctionLoc {
                            container,
                            ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)),
                        }
                        .intern(db)
                        .into();
                        (name, def)
                    }
                    ast::ImplItem::ConstDef(it) => {
                        let name = it.name().map_or_else(Name::missing, |it| it.as_name());
                        let def = ConstLoc {
                            container,
                            ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)),
                        }
                        .intern(db)
                        .into();
                        (name, def)
                    }
                    ast::ImplItem::TypeAliasDef(it) => {
                        let name = it.name().map_or_else(Name::missing, |it| it.as_name());
                        let def = TypeAliasLoc {
                            container,
                            ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)),
                        }
                        .intern(db)
                        .into();
                        (name, def)
                    }
                })
                .collect()
        } else {
            Vec::new()
        };
        Arc::new(TraitData { name, items, auto })
    }

    pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
        self.items.iter().filter_map(|(_name, item)| match item {
            AssocItemId::TypeAliasId(t) => Some(*t),
            _ => None,
        })
    }

    pub fn associated_type_by_name(&self, name: &Name) -> Option<TypeAliasId> {
        self.items.iter().find_map(|(item_name, item)| match item {
            AssocItemId::TypeAliasId(t) if item_name == name => Some(*t),
            _ => None,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ImplData {
    pub target_trait: Option<TypeRef>,
    pub target_type: TypeRef,
    pub items: Vec<AssocItemId>,
    pub is_negative: bool,
}

impl ImplData {
    pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> {
        let _p = profile("impl_data_query");
        let impl_loc = id.lookup(db);
        let src = impl_loc.source(db);

        let target_trait = src.value.target_trait().map(TypeRef::from_ast);
        let target_type = TypeRef::from_ast_opt(src.value.target_type());
        let is_negative = src.value.excl_token().is_some();
        let module_id = impl_loc.container.module(db);

        let mut items = Vec::new();

        if let Some(item_list) = src.value.item_list() {
            let mut expander = Expander::new(db, impl_loc.ast_id.file_id, module_id);
            items.extend(collect_impl_items(
                db,
                &mut expander,
                item_list.impl_items(),
                src.file_id,
                id,
            ));
            items.extend(collect_impl_items_in_macros(
                db,
                &mut expander,
                &src.with_value(item_list),
                id,
            ));
        }

        let res = ImplData { target_trait, target_type, items, is_negative };
        Arc::new(res)
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ConstData {
    /// const _: () = ();
    pub name: Option<Name>,
    pub type_ref: TypeRef,
    pub visibility: RawVisibility,
}

impl ConstData {
    pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> {
        let loc = konst.lookup(db);
        let node = loc.source(db);
        let vis_default = RawVisibility::default_for_container(loc.container);
        Arc::new(ConstData::new(db, vis_default, node))
    }

    pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<ConstData> {
        let node = konst.lookup(db).source(db);
        Arc::new(ConstData::new(db, RawVisibility::private(), node))
    }

    fn new<N: NameOwner + TypeAscriptionOwner + VisibilityOwner>(
        db: &dyn DefDatabase,
        vis_default: RawVisibility,
        node: InFile<N>,
    ) -> ConstData {
        let name = node.value.name().map(|n| n.as_name());
        let type_ref = TypeRef::from_ast_opt(node.value.ascribed_type());
        let visibility =
            RawVisibility::from_ast_with_default(db, vis_default, node.map(|n| n.visibility()));
        ConstData { name, type_ref, visibility }
    }
}

fn collect_impl_items_in_macros(
    db: &dyn DefDatabase,
    expander: &mut Expander,
    impl_def: &InFile<ast::ItemList>,
    id: ImplId,
) -> Vec<AssocItemId> {
    let mut res = Vec::new();

    // We set a limit to protect against infinite recursion
    let limit = 100;

    for m in impl_def.value.syntax().children().filter_map(ast::MacroCall::cast) {
        res.extend(collect_impl_items_in_macro(db, expander, m, id, limit))
    }

    res
}

fn collect_impl_items_in_macro(
    db: &dyn DefDatabase,
    expander: &mut Expander,
    m: ast::MacroCall,
    id: ImplId,
    limit: usize,
) -> Vec<AssocItemId> {
    if limit == 0 {
        return Vec::new();
    }

    if let Some((mark, items)) = expander.enter_expand(db, None, m) {
        let items: InFile<ast::MacroItems> = expander.to_source(items);
        let mut res = collect_impl_items(
            db,
            expander,
            items.value.items().filter_map(|it| ImplItem::cast(it.syntax().clone())),
            items.file_id,
            id,
        );
        // Recursive collect macros
        // Note that ast::ModuleItem do not include ast::MacroCall
        // We cannot use ModuleItemOwner::items here
        for it in items.value.syntax().children().filter_map(ast::MacroCall::cast) {
            res.extend(collect_impl_items_in_macro(db, expander, it, id, limit - 1))
        }
        expander.exit(db, mark);
        res
    } else {
        Vec::new()
    }
}

fn collect_impl_items(
    db: &dyn DefDatabase,
    expander: &mut Expander,
    impl_items: impl Iterator<Item = ImplItem>,
    file_id: crate::HirFileId,
    id: ImplId,
) -> Vec<AssocItemId> {
    let items = db.ast_id_map(file_id);

    impl_items
        .filter_map(|item_node| match item_node {
            ast::ImplItem::FnDef(it) => {
                let attrs = expander.parse_attrs(&it);
                if !expander.check_cfg(&attrs) {
                    return None;
                }
                let def = FunctionLoc {
                    container: AssocContainerId::ImplId(id),
                    ast_id: AstId::new(file_id, items.ast_id(&it)),
                }
                .intern(db);
                Some(def.into())
            }
            ast::ImplItem::ConstDef(it) => {
                let def = ConstLoc {
                    container: AssocContainerId::ImplId(id),
                    ast_id: AstId::new(file_id, items.ast_id(&it)),
                }
                .intern(db);
                Some(def.into())
            }
            ast::ImplItem::TypeAliasDef(it) => {
                let def = TypeAliasLoc {
                    container: AssocContainerId::ImplId(id),
                    ast_id: AstId::new(file_id, items.ast_id(&it)),
                }
                .intern(db);
                Some(def.into())
            }
        })
        .collect()
}
<|endoftext|>


<commit_before>//! Handling of DICOM values with the PN (person name) value representation
//! as per PS3.5 sect 6.2.
use std::fmt::{Display, Formatter};

/// A DICOM _Person Name_ (PN value representation).
///
/// Values of this type keep
/// family name, given name, middle name, prefix and suffix
/// as borrowed values.
/// All name components are optional.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct PersonName<'a> {
    prefix: Option<&'a str>,
    family: Option<&'a str>,
    middle: Option<&'a str>,
    given: Option<&'a str>,
    suffix: Option<&'a str>,
}

/// A builder to construct a [`PersonName`] from its components.
#[derive(Debug, Copy, Clone)]
pub struct PersonNameBuilder<'a> {
    person_name: PersonName<'a>,
}

impl Display for PersonName<'_> {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        let components: &[Option<&str>] = &[
            self.prefix,
            self.given,
            self.middle,
            self.family,
            self.suffix,
        ];

        let mut c_iter = components.iter().flatten().peekable();

        while let Some(component) = c_iter.next() {
            if c_iter.peek().is_some() {
                write!(f, "{} ", component)?
            } else {
                write!(f, "{}", component)?
            }
        }
        Ok(())
    }
}

impl<'a> PersonName<'a> {
    /// Retrieve PersonName prefix
    pub fn prefix(&self) -> Option<&str> {
        self.prefix
    }
    /// Retrieve PersonName suffix
    pub fn suffix(&self) -> Option<&str> {
        self.suffix
    }
    /// Retrieve family name from PersonName
    pub fn family(&self) -> Option<&str> {
        self.family
    }
    /// Retrieve given name from PersonName
    pub fn given(&self) -> Option<&str> {
        self.given
    }
    /// Retrieve middle name from PersonName
    pub fn middle(&self) -> Option<&str> {
        self.middle
    }
    /// Convert the person name into a DICOM formatted string.
    ///
    /// Name components are interspersed with a `'^'` separator.
    /// Leading null components produce a separator,
    /// while trailing components do not.
    pub fn to_dicom_string(&self) -> String {
        let mut name = String::new();

        let components: &[Option<&str>] = &[
            self.family,
            self.given,
            self.middle,
            self.prefix,
            self.suffix,
        ];

        let mut it  = components.iter().rev().peekable();
        // consume trailing None (null) components
        while it.next_if(|component| component.is_none()).is_some(){}

        let mut it = it.rev().peekable();
        while let Some(option) = it.next() {
            if let Some(component) = option {
                name.push_str(component);
            }
            if it.peek().is_some() {
                name.push('^');
            }
        }

        name
    }
    /// Retrieves a PersonName from a Dicom formatted string slice.
    /// The Dicom string representation is split by '^' separator into its respective components.
    pub fn from_slice(slice: &'a str) -> PersonName<'a> {
        let mut parts = slice.split('^');

        macro_rules! get_component {
            () => {
                parts
                    .next()
                    .and_then(|s| if s.is_empty() { None } else { Some(s) })
            };
        }

        let family = get_component!();
        let given = get_component!();
        let middle = get_component!();
        let prefix = get_component!();
        let suffix = get_component!();

        PersonName {
            prefix,
            given,
            family,
            middle,
            suffix,
        }
    }
    /// Retrieve a builder for a PersonName
    pub fn builder() -> PersonNameBuilder<'a> {
        PersonNameBuilder::new()
    }
}

impl<'a> PersonNameBuilder<'a> {
    pub fn new() -> PersonNameBuilder<'a> {
        PersonNameBuilder {
            person_name: PersonName {
                prefix: None,
                family: None,
                middle: None,
                given: None,
                suffix: None,
            },
        }
    }

    /// Insert or update the family name component.
    pub fn with_family(&mut self, family_name: &'a str) -> &mut Self {
        self.person_name.family = Some(family_name);
        self
    }

    /// Insert or update the middle name component.
    pub fn with_middle(&mut self, middle_name: &'a str) -> &mut Self {
        self.person_name.middle = Some(middle_name);
        self
    }

    /// Insert or update the given name component.
    pub fn with_given(&mut self, given_name: &'a str) -> &mut Self {
        self.person_name.given = Some(given_name);
        self
    }

    /// Insert or update the prefix component.
    pub fn with_prefix(&mut self, name_prefix: &'a str) -> &mut Self {
        self.person_name.prefix = Some(name_prefix);
        self
    }

    /// Insert or update the suffix component.
    pub fn with_suffix(&mut self, name_suffix: &'a str) -> &mut Self {
        self.person_name.suffix = Some(name_suffix);
        self
    }

    /// Builds the person name with the accumulated components.
    pub fn build(&self) -> PersonName<'a> {
        self.person_name
    }
}

impl<'a> Default for PersonNameBuilder<'a> {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_person_name_to_dicom_string() {
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: None,
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "Adams^John".to_string());

        let p = PersonName {
            prefix: Some("Rev."),
            given: None,
            middle: None,
            family: None,
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "^^^Rev.".to_string());
        let p = PersonName {
            prefix: None,
            given: None,
            middle: None,
            family: None,
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(p.to_dicom_string(), "^^^^B.A. M.Div.".to_string());
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(
            p.to_dicom_string(),
            "Adams^John^Robert^Rev.^B.A. M.Div.".to_string()
        );
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(
            p.to_dicom_string(),
            "Adams^John^Robert^^B.A. M.Div.".to_string()
        );
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "Adams^John^Robert^Rev.".to_string());
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "Adams^John^Robert".to_string());
        let p = PersonName {
            prefix: None,
            given: None,
            middle: Some("Robert"),
            family: None,
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "^^Robert".to_string());
    }
    #[test]
    fn test_person_name_to_string() {
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: None,
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_string(), "John Adams".to_string());

        let p = PersonName {
            prefix: Some("Rev."),
            given: None,
            middle: None,
            family: None,
            suffix: None,
        };
        assert_eq!(p.to_string(), "Rev.".to_string());

        let p = PersonName {
            prefix: None,
            given: None,
            middle: None,
            family: None,
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(p.to_string(), "B.A. M.Div.".to_string());
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(
            p.to_string(),
            "Rev. John Robert Adams B.A. M.Div.".to_string()
        );
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(p.to_string(), "John Robert Adams B.A. M.Div.".to_string());
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_string(), "Rev. John Robert Adams".to_string());
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_string(), "John Robert Adams".to_string());
        let p = PersonName {
            prefix: None,
            given: None,
            middle: Some("Robert"),
            family: None,
            suffix: None,
        };
        assert_eq!(p.to_string(), "Robert".to_string());
    }
    #[test]
    fn person_name_from_slice() {
        assert_eq!(
            PersonName::from_slice("^^Robert"),
            PersonName {
                prefix: None,
                given: None,
                middle: Some("Robert"),
                family: None,
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("^^^Rev."),
            PersonName {
                prefix: Some("Rev."),
                given: None,
                middle: None,
                family: None,
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("^^^^B.A. M.Div."),
            PersonName {
                prefix: None,
                given: None,
                middle: None,
                family: None,
                suffix: Some("B.A. M.Div."),
            }
        );
        assert_eq!(
            PersonName::from_slice("^^Robert"),
            PersonName {
                prefix: None,
                given: None,
                middle: Some("Robert"),
                family: None,
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("^John"),
            PersonName {
                prefix: None,
                given: Some("John"),
                middle: None,
                family: None,
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("Adams"),
            PersonName {
                prefix: None,
                given: None,
                middle: None,
                family: Some("Adams"),
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("Adams^^^^B.A. M.Div."),
            PersonName {
                prefix: None,
                given: None,
                middle: None,
                family: Some("Adams"),
                suffix: Some("B.A. M.Div."),
            }
        );
        assert_eq!(
            PersonName::from_slice("Adams^^Robert^^B.A. M.Div."),
            PersonName {
                prefix: None,
                given: None,
                middle: Some("Robert"),
                family: Some("Adams"),
                suffix: Some("B.A. M.Div."),
            }
        );
        assert_eq!(
            PersonName::from_slice("Adams^John^Robert^Rev.^B.A. M.Div."),
            PersonName {
                prefix: Some("Rev."),
                given: Some("John"),
                middle: Some("Robert"),
                family: Some("Adams"),
                suffix: Some("B.A. M.Div."),
            }
        );
    }
}
<commit_msg>[core] Add From builder impls for PersonName<commit_after>//! Handling of DICOM values with the PN (person name) value representation
//! as per PS3.5 sect 6.2.
use std::fmt::{Display, Formatter};

/// A DICOM _Person Name_ (PN value representation).
///
/// Values of this type keep
/// family name, given name, middle name, prefix and suffix
/// as borrowed values.
/// All name components are optional.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct PersonName<'a> {
    prefix: Option<&'a str>,
    family: Option<&'a str>,
    middle: Option<&'a str>,
    given: Option<&'a str>,
    suffix: Option<&'a str>,
}

/// A builder to construct a [`PersonName`] from its components.
#[derive(Debug, Copy, Clone)]
pub struct PersonNameBuilder<'a> {
    person_name: PersonName<'a>,
}

impl Display for PersonName<'_> {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        let components: &[Option<&str>] = &[
            self.prefix,
            self.given,
            self.middle,
            self.family,
            self.suffix,
        ];

        let mut c_iter = components.iter().flatten().peekable();

        while let Some(component) = c_iter.next() {
            if c_iter.peek().is_some() {
                write!(f, "{} ", component)?
            } else {
                write!(f, "{}", component)?
            }
        }
        Ok(())
    }
}

impl<'a> PersonName<'a> {
    /// Retrieve PersonName prefix
    pub fn prefix(&self) -> Option<&str> {
        self.prefix
    }
    /// Retrieve PersonName suffix
    pub fn suffix(&self) -> Option<&str> {
        self.suffix
    }
    /// Retrieve family name from PersonName
    pub fn family(&self) -> Option<&str> {
        self.family
    }
    /// Retrieve given name from PersonName
    pub fn given(&self) -> Option<&str> {
        self.given
    }
    /// Retrieve middle name from PersonName
    pub fn middle(&self) -> Option<&str> {
        self.middle
    }
    /// Convert the person name into a DICOM formatted string.
    ///
    /// Name components are interspersed with a `'^'` separator.
    /// Leading null components produce a separator,
    /// while trailing components do not.
    pub fn to_dicom_string(&self) -> String {
        let mut name = String::new();

        let components: &[Option<&str>] = &[
            self.family,
            self.given,
            self.middle,
            self.prefix,
            self.suffix,
        ];

        let mut it  = components.iter().rev().peekable();
        // consume trailing None (null) components
        while it.next_if(|component| component.is_none()).is_some(){}

        let mut it = it.rev().peekable();
        while let Some(option) = it.next() {
            if let Some(component) = option {
                name.push_str(component);
            }
            if it.peek().is_some() {
                name.push('^');
            }
        }

        name
    }
    /// Retrieves a PersonName from a Dicom formatted string slice.
    /// The Dicom string representation is split by '^' separator into its respective components.
    pub fn from_slice(slice: &'a str) -> PersonName<'a> {
        let mut parts = slice.split('^');

        macro_rules! get_component {
            () => {
                parts
                    .next()
                    .and_then(|s| if s.is_empty() { None } else { Some(s) })
            };
        }

        let family = get_component!();
        let given = get_component!();
        let middle = get_component!();
        let prefix = get_component!();
        let suffix = get_component!();

        PersonName {
            prefix,
            given,
            family,
            middle,
            suffix,
        }
    }
    /// Retrieve a builder for a PersonName
    pub fn builder() -> PersonNameBuilder<'a> {
        PersonNameBuilder::new()
    }
}

impl<'a> PersonNameBuilder<'a> {
    pub fn new() -> PersonNameBuilder<'a> {
        PersonNameBuilder {
            person_name: PersonName {
                prefix: None,
                family: None,
                middle: None,
                given: None,
                suffix: None,
            },
        }
    }

    /// Insert or update the family name component.
    pub fn with_family(&mut self, family_name: &'a str) -> &mut Self {
        self.person_name.family = Some(family_name);
        self
    }

    /// Insert or update the middle name component.
    pub fn with_middle(&mut self, middle_name: &'a str) -> &mut Self {
        self.person_name.middle = Some(middle_name);
        self
    }

    /// Insert or update the given name component.
    pub fn with_given(&mut self, given_name: &'a str) -> &mut Self {
        self.person_name.given = Some(given_name);
        self
    }

    /// Insert or update the prefix component.
    pub fn with_prefix(&mut self, name_prefix: &'a str) -> &mut Self {
        self.person_name.prefix = Some(name_prefix);
        self
    }

    /// Insert or update the suffix component.
    pub fn with_suffix(&mut self, name_suffix: &'a str) -> &mut Self {
        self.person_name.suffix = Some(name_suffix);
        self
    }

    /// Builds the person name with the accumulated components.
    pub fn build(&self) -> PersonName<'a> {
        self.person_name
    }
}

impl<'a> Default for PersonNameBuilder<'a> {
    fn default() -> Self {
        Self::new()
    }
}

impl<'a> From<PersonNameBuilder<'a>> for PersonName<'a> {
    fn from(builder: PersonNameBuilder<'a>) -> Self {
        builder.build()
    }
}

impl<'a> From<&mut PersonNameBuilder<'a>> for PersonName<'a> {
    fn from(builder: &mut PersonNameBuilder<'a>) -> Self {
        builder.build()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_person_name_to_dicom_string() {
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: None,
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "Adams^John".to_string());

        let p = PersonName {
            prefix: Some("Rev."),
            given: None,
            middle: None,
            family: None,
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "^^^Rev.".to_string());
        let p = PersonName {
            prefix: None,
            given: None,
            middle: None,
            family: None,
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(p.to_dicom_string(), "^^^^B.A. M.Div.".to_string());
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(
            p.to_dicom_string(),
            "Adams^John^Robert^Rev.^B.A. M.Div.".to_string()
        );
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(
            p.to_dicom_string(),
            "Adams^John^Robert^^B.A. M.Div.".to_string()
        );
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "Adams^John^Robert^Rev.".to_string());
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "Adams^John^Robert".to_string());
        let p = PersonName {
            prefix: None,
            given: None,
            middle: Some("Robert"),
            family: None,
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "^^Robert".to_string());
    }
    #[test]
    fn test_person_name_to_string() {
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: None,
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_string(), "John Adams".to_string());

        let p = PersonName {
            prefix: Some("Rev."),
            given: None,
            middle: None,
            family: None,
            suffix: None,
        };
        assert_eq!(p.to_string(), "Rev.".to_string());

        let p = PersonName {
            prefix: None,
            given: None,
            middle: None,
            family: None,
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(p.to_string(), "B.A. M.Div.".to_string());
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(
            p.to_string(),
            "Rev. John Robert Adams B.A. M.Div.".to_string()
        );
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(p.to_string(), "John Robert Adams B.A. M.Div.".to_string());
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_string(), "Rev. John Robert Adams".to_string());
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_string(), "John Robert Adams".to_string());
        let p = PersonName {
            prefix: None,
            given: None,
            middle: Some("Robert"),
            family: None,
            suffix: None,
        };
        assert_eq!(p.to_string(), "Robert".to_string());
    }
    #[test]
    fn person_name_from_slice() {
        assert_eq!(
            PersonName::from_slice("^^Robert"),
            PersonName {
                prefix: None,
                given: None,
                middle: Some("Robert"),
                family: None,
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("^^^Rev."),
            PersonName {
                prefix: Some("Rev."),
                given: None,
                middle: None,
                family: None,
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("^^^^B.A. M.Div."),
            PersonName {
                prefix: None,
                given: None,
                middle: None,
                family: None,
                suffix: Some("B.A. M.Div."),
            }
        );
        assert_eq!(
            PersonName::from_slice("^^Robert"),
            PersonName {
                prefix: None,
                given: None,
                middle: Some("Robert"),
                family: None,
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("^John"),
            PersonName {
                prefix: None,
                given: Some("John"),
                middle: None,
                family: None,
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("Adams"),
            PersonName {
                prefix: None,
                given: None,
                middle: None,
                family: Some("Adams"),
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("Adams^^^^B.A. M.Div."),
            PersonName {
                prefix: None,
                given: None,
                middle: None,
                family: Some("Adams"),
                suffix: Some("B.A. M.Div."),
            }
        );
        assert_eq!(
            PersonName::from_slice("Adams^^Robert^^B.A. M.Div."),
            PersonName {
                prefix: None,
                given: None,
                middle: Some("Robert"),
                family: Some("Adams"),
                suffix: Some("B.A. M.Div."),
            }
        );
        assert_eq!(
            PersonName::from_slice("Adams^John^Robert^Rev.^B.A. M.Div."),
            PersonName {
                prefix: Some("Rev."),
                given: Some("John"),
                middle: Some("Robert"),
                family: Some("Adams"),
                suffix: Some("B.A. M.Div."),
            }
        );
    }
}
<|endoftext|>