<commit_before>//! TODO: Docs

use std::collections::VecDeque;

use indexmap::IndexMap;

use crate::{
    backend::renderer::Frame,
    output::Output,
    utils::{Physical, Rectangle, Scale, Size, Transform},
};

use super::element::{Id, RenderElement};

use super::{ImportAll, Renderer, Texture};

#[derive(Debug, Clone, Copy)]
struct ElementState {
    last_commit: usize,
    last_geometry: Rectangle<i32, Physical>,
    last_z_index: usize,
}

#[derive(Debug, Default)]
struct RendererState {
    size: Option<Size<i32, Physical>>,
    elements: IndexMap<Id, ElementState>,
    old_damage: VecDeque<Vec<Rectangle<i32, Physical>>>,
}

/// Mode for the [`DamageTrackedRenderer`]
#[derive(Debug, Clone)]
pub enum DamageTrackedRendererMode {
    /// Automatic mode based on a output
    Auto(Output),
    /// Static mode
    Static {
        /// Size of the static output
        size: Size<i32, Physical>,
        /// Scale of the static output
        scale: Scale<f64>,
        /// Transform of the static output
        transform: Transform,
    },
}

/// Output has no active mode
#[derive(Debug, thiserror::Error)]
#[error("Output has no active mode")]
pub struct OutputNoMode;

impl TryInto<(Size<i32, Physical>, Scale<f64>, Transform)> for DamageTrackedRendererMode {
    type Error = OutputNoMode;

    fn try_into(self) -> Result<(Size<i32, Physical>, Scale<f64>, Transform), Self::Error> {
        match self {
            DamageTrackedRendererMode::Auto(output) => Ok((
                output.current_mode().ok_or(OutputNoMode)?.size,
                output.current_scale().fractional_scale().into(),
                output.current_transform(),
            )),
            DamageTrackedRendererMode::Static {
                size,
                scale,
                transform,
            } => Ok((size, scale, transform)),
        }
    }
}

/// Rendering for a single output
#[derive(Debug)]
pub struct DamageTrackedRenderer {
    mode: DamageTrackedRendererMode,
    last_state: RendererState,
}

/// Errors thrown by [`Space::render_output`]
#[derive(thiserror::Error)]
pub enum DamageTrackedRendererError<R: Renderer> {
    /// The provided [`Renderer`] did return an error during an operation
    #[error(transparent)]
    Rendering(R::Error),
    /// The given [`Output`] has no set mode
    #[error(transparent)]
    OutputNoMode(#[from] OutputNoMode),
}

impl<R: Renderer> std::fmt::Debug for DamageTrackedRendererError<R> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            DamageTrackedRendererError::Rendering(err) => std::fmt::Debug::fmt(err, f),
            DamageTrackedRendererError::OutputNoMode(err) => std::fmt::Debug::fmt(err, f),
        }
    }
}

impl DamageTrackedRenderer {
    /// Initialize a new [`DamageTrackedRenderer`]
    pub fn new(size: Size<i32, Physical>, scale: impl Into<Scale<f64>>, transform: Transform) -> Self {
        Self {
            mode: DamageTrackedRendererMode::Static {
                size,
                scale: scale.into(),
                transform,
            },
            last_state: Default::default(),
        }
    }

    /// Initialize a new [`DamageTrackedRenderer`]
    pub fn from_output(output: &Output) -> Self {
        Self {
            mode: DamageTrackedRendererMode::Auto(output.clone()),
            last_state: Default::default(),
        }
    }

    /// Get the [`Mode`] of the [`DamageTrackedRenderer`]
    pub fn mode(&self) -> &DamageTrackedRendererMode {
        &self.mode
    }

    /// Render this output
    pub fn render_output<E, R>(
        &mut self,
        renderer: &mut R,
        age: usize,
        elements: &[E],
        clear_color: [f32; 4],
        log: &slog::Logger,
    ) -> Result<Option<Vec<Rectangle<i32, Physical>>>, DamageTrackedRendererError<R>>
    where
        E: RenderElement<R>,
        R: Renderer + ImportAll,
        <R as Renderer>::TextureId: Texture,
    {
        let (output_size, output_scale, output_transform) = self.mode.clone().try_into()?;
        let output_geo = Rectangle::from_loc_and_size((0, 0), output_size);

        // This will hold all the damage we need for this rendering step
        let mut damage: Vec<Rectangle<i32, Physical>> = Vec::new();
        let mut render_elements: Vec<&E> = Vec::with_capacity(elements.len());
        let mut opaque_regions: Vec<Rectangle<i32, Physical>> = Vec::new();

        if self.last_state.size.map(|geo| geo != output_size).unwrap_or(true) {
            // The output geometry changed, so just damage everything
            slog::trace!(log, "Output geometry changed, damaging whole output geometry. previous geometry: {:?}, current geometry: {:?}", self.last_state.size, output_geo);
            damage = vec![output_geo];
        }

        // We now add old damage states, if we have an age value
        if age > 0 && self.last_state.old_damage.len() >= age {
            // We do not need even older states anymore
            self.last_state.old_damage.truncate(age);
            damage.extend(self.last_state.old_damage.iter().flatten().copied());
        } else {
            // just damage everything, if we have no damage
            damage = vec![output_geo];
        }

        for element in elements {
            let element_geometry = element.geometry(output_scale);

            // First test if the element overlaps with the output
            // if not we can skip ip
            if !element_geometry.overlaps(output_geo) {
                continue;
            }

            // Then test if the element is completely hidden behind opaque regions
            let is_hidden = opaque_regions
                .iter()
                .fold([element_geometry].to_vec(), |geometry, opaque_region| {
                    geometry
                        .into_iter()
                        .flat_map(|g| g.subtract_rect(*opaque_region))
                        .collect::<Vec<_>>()
                })
                .is_empty();

            if is_hidden {
                // No need to draw a completely hidden element
                continue;
            }

            let element_damage = element
                .damage_since(
                    output_scale,
                    self.last_state.elements.get(element.id()).map(|s| s.last_commit),
                )
                .into_iter()
                .map(|mut d| {
                    d.loc += element_geometry.loc;
                    d
                })
                .collect::<Vec<_>>();

            let element_output_damage =
                opaque_regions
                    .iter()
                    .fold(element_damage, |damage, opaque_region| {
                        damage
                            .into_iter()
                            .flat_map(|damage| damage.subtract_rect(*opaque_region))
                            .collect::<Vec<_>>()
                    });

            damage.extend(element_output_damage);
            opaque_regions.extend(
                element
                    .opaque_regions(output_scale)
                    .into_iter()
                    .map(|mut region| {
                        region.loc += element_geometry.loc;
                        region
                    }),
            );
            render_elements.insert(0, element);
        }

        // add the damage for elements gone that are not covered by
        // by an opaque region
        // TODO: actually filter the damage with the opaque regions
        let elements_gone = self
            .last_state
            .elements
            .iter()
            .filter_map(|(id, state)| {
                if !render_elements.iter().any(|e| e.id() == id) {
                    Some(state.last_geometry)
                } else {
                    None
                }
            })
            .collect::<Vec<_>>();
        damage.extend(elements_gone);

        // if the element has been moved or it's z index changed damage it
        for (z_index, element) in render_elements.iter().enumerate() {
            let element_geometry = element.geometry(output_scale);
            let element_last_state = self.last_state.elements.get(element.id());

            if element_last_state
                .map(|s| s.last_geometry != element_geometry || s.last_z_index != z_index)
                .unwrap_or(false)
            {
                if let Some(old_geo) = element_last_state.map(|s| s.last_geometry) {
                    damage.push(old_geo);
                }
                damage.push(element_geometry);
            }
        }

        // Optimize the damage for rendering
        damage.dedup();
        damage.retain(|rect| rect.overlaps(output_geo));
        damage.retain(|rect| !rect.is_empty());
        // filter damage outside of the output gep and merge overlapping rectangles
        damage = damage
            .into_iter()
            .filter_map(|rect| rect.intersection(output_geo))
            .fold(Vec::new(), |new_damage, mut rect| {
                // replace with drain_filter, when that becomes stable to reuse the original Vec's memory
                let (overlapping, mut new_damage): (Vec<_>, Vec<_>) =
                    new_damage.into_iter().partition(|other| other.overlaps(rect));

                for overlap in overlapping {
                    rect = rect.merge(overlap);
                }
                new_damage.push(rect);
                new_damage
            });

        if damage.is_empty() {
            return Ok(None);
        }

        let mut elements_drawn = 0;

        let res = renderer.render(output_size, output_transform, |renderer, frame| {
            frame.clear(clear_color, &*damage)?;

            for element in render_elements.iter() {
                let element_geometry = element.geometry(output_scale);

                let element_damage = damage
                    .iter()
                    .filter_map(|d| d.intersection(element_geometry))
                    .map(|mut d| {
                        d.loc -= element_geometry.loc;
                        d
                    })
                    .collect::<Vec<_>>();

                if element_damage.is_empty() {
                    continue;
                }

                element.draw(renderer, frame, output_scale, &*element_damage, log)?;
                elements_drawn += 1;
            }

            Result::<(), R::Error>::Ok(())
        });

        if let Err(err) = res {
            // if the rendering errors on us, we need to be prepared, that this whole buffer was partially updated and thus now unusable.
            // thus clean our old states before returning
            self.last_state = Default::default();
            return Err(DamageTrackedRendererError::Rendering(err));
        }

        let new_elements_state = render_elements
            .iter()
            .enumerate()
            .map(|(zindex, elem)| {
                let id = elem.id().clone();
                let current_commit = elem.current_commit();
                let elem_geometry = elem.geometry(output_scale);
                let state = ElementState {
                    last_commit: current_commit,
                    last_geometry: elem_geometry,
                    last_z_index: zindex,
                };
                (id, state)
            })
            .collect();
        self.last_state.size = Some(output_size);
        self.last_state.elements = new_elements_state;
        self.last_state.old_damage.push_front(damage.clone());

        Ok(Some(damage))
    }
}
<commit_msg>renderer: lift the renderer constraints<commit_after>//! TODO: Docs

use std::collections::VecDeque;

use indexmap::IndexMap;

use crate::{
    backend::renderer::Frame,
    output::Output,
    utils::{Physical, Rectangle, Scale, Size, Transform},
};

use super::element::{Id, RenderElement};

use super::{Renderer, Texture};

#[derive(Debug, Clone, Copy)]
struct ElementState {
    last_commit: usize,
    last_geometry: Rectangle<i32, Physical>,
    last_z_index: usize,
}

#[derive(Debug, Default)]
struct RendererState {
    size: Option<Size<i32, Physical>>,
    elements: IndexMap<Id, ElementState>,
    old_damage: VecDeque<Vec<Rectangle<i32, Physical>>>,
}

/// Mode for the [`DamageTrackedRenderer`]
#[derive(Debug, Clone)]
pub enum DamageTrackedRendererMode {
    /// Automatic mode based on a output
    Auto(Output),
    /// Static mode
    Static {
        /// Size of the static output
        size: Size<i32, Physical>,
        /// Scale of the static output
        scale: Scale<f64>,
        /// Transform of the static output
        transform: Transform,
    },
}

/// Output has no active mode
#[derive(Debug, thiserror::Error)]
#[error("Output has no active mode")]
pub struct OutputNoMode;

impl TryInto<(Size<i32, Physical>, Scale<f64>, Transform)> for DamageTrackedRendererMode {
    type Error = OutputNoMode;

    fn try_into(self) -> Result<(Size<i32, Physical>, Scale<f64>, Transform), Self::Error> {
        match self {
            DamageTrackedRendererMode::Auto(output) => Ok((
                output.current_mode().ok_or(OutputNoMode)?.size,
                output.current_scale().fractional_scale().into(),
                output.current_transform(),
            )),
            DamageTrackedRendererMode::Static {
                size,
                scale,
                transform,
            } => Ok((size, scale, transform)),
        }
    }
}

/// Rendering for a single output
#[derive(Debug)]
pub struct DamageTrackedRenderer {
    mode: DamageTrackedRendererMode,
    last_state: RendererState,
}

/// Errors thrown by [`Space::render_output`]
#[derive(thiserror::Error)]
pub enum DamageTrackedRendererError<R: Renderer> {
    /// The provided [`Renderer`] did return an error during an operation
    #[error(transparent)]
    Rendering(R::Error),
    /// The given [`Output`] has no set mode
    #[error(transparent)]
    OutputNoMode(#[from] OutputNoMode),
}

impl<R: Renderer> std::fmt::Debug for DamageTrackedRendererError<R> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            DamageTrackedRendererError::Rendering(err) => std::fmt::Debug::fmt(err, f),
            DamageTrackedRendererError::OutputNoMode(err) => std::fmt::Debug::fmt(err, f),
        }
    }
}

impl DamageTrackedRenderer {
    /// Initialize a new [`DamageTrackedRenderer`]
    pub fn new(
        size: impl Into<Size<i32, Physical>>,
        scale: impl Into<Scale<f64>>,
        transform: Transform,
    ) -> Self {
        Self {
            mode: DamageTrackedRendererMode::Static {
                size: size.into(),
                scale: scale.into(),
                transform,
            },
            last_state: Default::default(),
        }
    }

    /// Initialize a new [`DamageTrackedRenderer`]
    pub fn from_output(output: &Output) -> Self {
        Self {
            mode: DamageTrackedRendererMode::Auto(output.clone()),
            last_state: Default::default(),
        }
    }

    /// Get the [`Mode`] of the [`DamageTrackedRenderer`]
    pub fn mode(&self) -> &DamageTrackedRendererMode {
        &self.mode
    }

    /// Render this output
    pub fn render_output<E, R>(
        &mut self,
        renderer: &mut R,
        age: usize,
        elements: &[E],
        clear_color: [f32; 4],
        log: &slog::Logger,
    ) -> Result<Option<Vec<Rectangle<i32, Physical>>>, DamageTrackedRendererError<R>>
    where
        E: RenderElement<R>,
        R: Renderer,
        <R as Renderer>::TextureId: Texture,
    {
        let (output_size, output_scale, output_transform) = self.mode.clone().try_into()?;
        let output_geo = Rectangle::from_loc_and_size((0, 0), output_size);

        // This will hold all the damage we need for this rendering step
        let mut damage: Vec<Rectangle<i32, Physical>> = Vec::new();
        let mut render_elements: Vec<&E> = Vec::with_capacity(elements.len());
        let mut opaque_regions: Vec<Rectangle<i32, Physical>> = Vec::new();

        if self.last_state.size.map(|geo| geo != output_size).unwrap_or(true) {
            // The output geometry changed, so just damage everything
            slog::trace!(log, "Output geometry changed, damaging whole output geometry. previous geometry: {:?}, current geometry: {:?}", self.last_state.size, output_geo);
            damage = vec![output_geo];
        }

        // We now add old damage states, if we have an age value
        if age > 0 && self.last_state.old_damage.len() >= age {
            // We do not need even older states anymore
            self.last_state.old_damage.truncate(age);
            damage.extend(self.last_state.old_damage.iter().flatten().copied());
        } else {
            // just damage everything, if we have no damage
            damage = vec![output_geo];
        }

        for element in elements {
            let element_geometry = element.geometry(output_scale);

            // First test if the element overlaps with the output
            // if not we can skip ip
            if !element_geometry.overlaps(output_geo) {
                continue;
            }

            // Then test if the element is completely hidden behind opaque regions
            let is_hidden = opaque_regions
                .iter()
                .fold([element_geometry].to_vec(), |geometry, opaque_region| {
                    geometry
                        .into_iter()
                        .flat_map(|g| g.subtract_rect(*opaque_region))
                        .collect::<Vec<_>>()
                })
                .is_empty();

            if is_hidden {
                // No need to draw a completely hidden element
                continue;
            }

            let element_damage = element
                .damage_since(
                    output_scale,
                    self.last_state.elements.get(element.id()).map(|s| s.last_commit),
                )
                .into_iter()
                .map(|mut d| {
                    d.loc += element_geometry.loc;
                    d
                })
                .collect::<Vec<_>>();

            let element_output_damage =
                opaque_regions
                    .iter()
                    .fold(element_damage, |damage, opaque_region| {
                        damage
                            .into_iter()
                            .flat_map(|damage| damage.subtract_rect(*opaque_region))
                            .collect::<Vec<_>>()
                    });

            damage.extend(element_output_damage);
            opaque_regions.extend(
                element
                    .opaque_regions(output_scale)
                    .into_iter()
                    .map(|mut region| {
                        region.loc += element_geometry.loc;
                        region
                    }),
            );
            render_elements.insert(0, element);
        }

        // add the damage for elements gone that are not covered by
        // by an opaque region
        // TODO: actually filter the damage with the opaque regions
        let elements_gone = self
            .last_state
            .elements
            .iter()
            .filter_map(|(id, state)| {
                if !render_elements.iter().any(|e| e.id() == id) {
                    Some(state.last_geometry)
                } else {
                    None
                }
            })
            .collect::<Vec<_>>();
        damage.extend(elements_gone);

        // if the element has been moved or it's z index changed damage it
        for (z_index, element) in render_elements.iter().enumerate() {
            let element_geometry = element.geometry(output_scale);
            let element_last_state = self.last_state.elements.get(element.id());

            if element_last_state
                .map(|s| s.last_geometry != element_geometry || s.last_z_index != z_index)
                .unwrap_or(false)
            {
                if let Some(old_geo) = element_last_state.map(|s| s.last_geometry) {
                    damage.push(old_geo);
                }
                damage.push(element_geometry);
            }
        }

        // Optimize the damage for rendering
        damage.dedup();
        damage.retain(|rect| rect.overlaps(output_geo));
        damage.retain(|rect| !rect.is_empty());
        // filter damage outside of the output gep and merge overlapping rectangles
        damage = damage
            .into_iter()
            .filter_map(|rect| rect.intersection(output_geo))
            .fold(Vec::new(), |new_damage, mut rect| {
                // replace with drain_filter, when that becomes stable to reuse the original Vec's memory
                let (overlapping, mut new_damage): (Vec<_>, Vec<_>) =
                    new_damage.into_iter().partition(|other| other.overlaps(rect));

                for overlap in overlapping {
                    rect = rect.merge(overlap);
                }
                new_damage.push(rect);
                new_damage
            });

        if damage.is_empty() {
            return Ok(None);
        }

        let mut elements_drawn = 0;

        let res = renderer.render(output_size, output_transform, |renderer, frame| {
            frame.clear(clear_color, &*damage)?;

            for element in render_elements.iter() {
                let element_geometry = element.geometry(output_scale);

                let element_damage = damage
                    .iter()
                    .filter_map(|d| d.intersection(element_geometry))
                    .map(|mut d| {
                        d.loc -= element_geometry.loc;
                        d
                    })
                    .collect::<Vec<_>>();

                if element_damage.is_empty() {
                    continue;
                }

                element.draw(renderer, frame, output_scale, &*element_damage, log)?;
                elements_drawn += 1;
            }

            Result::<(), R::Error>::Ok(())
        });

        if let Err(err) = res {
            // if the rendering errors on us, we need to be prepared, that this whole buffer was partially updated and thus now unusable.
            // thus clean our old states before returning
            self.last_state = Default::default();
            return Err(DamageTrackedRendererError::Rendering(err));
        }

        let new_elements_state = render_elements
            .iter()
            .enumerate()
            .map(|(zindex, elem)| {
                let id = elem.id().clone();
                let current_commit = elem.current_commit();
                let elem_geometry = elem.geometry(output_scale);
                let state = ElementState {
                    last_commit: current_commit,
                    last_geometry: elem_geometry,
                    last_z_index: zindex,
                };
                (id, state)
            })
            .collect();
        self.last_state.size = Some(output_size);
        self.last_state.elements = new_elements_state;
        self.last_state.old_damage.push_front(damage.clone());

        Ok(Some(damage))
    }
}
<|endoftext|>


<commit_before>//! Implementation of `get_bytes` operation on `Buf`.
//!
//! See also [this PR](https://github.com/tokio-rs/bytes/pull/363).

use bytes::buf::ext::BufExt;
use bytes::buf::ext::Chain;
use bytes::buf::ext::Take;
use bytes::Buf;
use bytes::BufMut;
use bytes::Bytes;
use bytes::BytesMut;
use std::cmp;
use std::io::Cursor;

/// Get `Bytes` from `Buf`.
pub trait BufGetBytes: Buf {
    /// Consumes requested number of bytes from `self`.
    ///
    /// # Examples
    ///
    /// ```
    /// use bytes::Buf;
    /// use httpbis::BufGetBytes;
    ///
    /// let bytes = (&b"hello world"[..]).get_bytes(5);
    /// assert_eq!(&bytes[..], &b"hello"[..]);
    /// ```
    ///
    /// # Panics
    ///
    /// This function panics if there is not enough remaining data in `self`.
    fn get_bytes(&mut self, mut cnt: usize) -> Bytes {
        if cnt == 0 {
            return Bytes::new();
        }

        assert!(self.remaining() >= cnt);

        // Could be as simple as self.take(count).to_bytes()
        // but compiler stack overflows on instantiation of test Buf impl for some types

        let mut ret = BytesMut::with_capacity(cnt);

        while cnt != 0 {
            let bytes = self.bytes();
            let step = cmp::min(bytes.len(), cnt);
            ret.put_slice(&bytes[..step]);
            self.advance(step);
            cnt -= step;
        }

        ret.freeze()
    }
}

impl BufGetBytes for Bytes {
    fn get_bytes(&mut self, cnt: usize) -> Bytes {
        self.split_to(cnt)
    }
}

impl BufGetBytes for BytesMut {
    fn get_bytes(&mut self, cnt: usize) -> Bytes {
        self.split_to(cnt).freeze()
    }
}

impl BufGetBytes for &[u8] {}

impl<A: AsRef<[u8]>> BufGetBytes for Cursor<A> {}

impl<A: BufGetBytes, B: BufGetBytes> BufGetBytes for Chain<A, B> {
    fn get_bytes(&mut self, mut cnt: usize) -> Bytes {
        let a_rem = self.first_mut().remaining();
        if a_rem >= cnt {
            self.first_mut().get_bytes(cnt)
        } else if !self.first_mut().has_remaining() {
            self.last_mut().get_bytes(cnt)
        } else {
            assert!(cnt <= a_rem + self.last_mut().remaining());

            let mut ret = BytesMut::with_capacity(cnt);
            ret.put(self.first_mut());
            ret.put((self.last_mut()).take(cnt - a_rem));
            ret.freeze()
        }
    }
}

impl<A: BufGetBytes> BufGetBytes for Take<A> {
    fn get_bytes(&mut self, mut cnt: usize) -> Bytes {
        assert!(cnt <= self.remaining());
        let ret = self.get_mut().get_bytes(cnt);
        self.set_limit(self.limit() - cnt);
        ret
    }
}

impl<A: BufGetBytes> BufGetBytes for &mut A {
    fn get_bytes(&mut self, cnt: usize) -> Bytes {
        (&mut **self).get_bytes(cnt)
    }
}

#[cfg(test)]
mod test {
    use crate::bytes_ext::buf_get_bytes::BufGetBytes;
    use bytes::buf::BufExt;
    use bytes::Buf;
    use bytes::Bytes;
    use bytes::BytesMut;

    #[test]
    fn get_to_bytes() {
        let mut buf = &b"abcd"[..];
        assert_eq!(Bytes::copy_from_slice(b"abcd"), buf.to_bytes());
        assert_eq!(b"", buf);
    }

    #[test]
    fn get_get_bytes() {
        let mut buf = &b"abcd"[..];
        assert_eq!(Bytes::copy_from_slice(b"abc"), buf.get_bytes(3));
        assert_eq!(b"d", buf);
    }

    #[test]
    fn bytes_get_bytes() {
        let mut bytes = Bytes::from(b"abc".to_vec());

        let a = bytes.get_bytes(1);
        assert_eq!(b"a", a.as_ref());
        // assert returned bytes object is a subslice of original bytes object
        assert_eq!(
            a.as_ref().as_ptr() as usize + 1,
            bytes.as_ref().as_ptr() as usize
        );

        let bc = bytes.get_bytes(2);
        assert_eq!(b"bc", bc.as_ref());
        // assert returned bytes object is a subslice of original bytes object
        assert_eq!(
            bc.as_ref().as_ptr() as usize,
            a.as_ref().as_ptr() as usize + 1
        );

        assert_eq!(Bytes::new(), bytes);
    }

    #[test]
    fn bytes_mut_get_bytes() {
        let mut bytes = BytesMut::from(&b"abc"[..]);

        let a = bytes.get_bytes(1);
        assert_eq!(b"a", a.as_ref());
        // assert returned bytes object is a subslice of original bytes object
        assert_eq!(
            a.as_ref().as_ptr() as usize + 1,
            bytes.as_ref().as_ptr() as usize
        );

        let bc = bytes.get_bytes(2);
        assert_eq!(b"bc", bc.as_ref());
        // assert returned bytes object is a subslice of original bytes object
        assert_eq!(
            bc.as_ref().as_ptr() as usize,
            a.as_ref().as_ptr() as usize + 1
        );

        assert_eq!(BytesMut::new(), bytes);
    }

    #[test]
    fn chain_to_bytes() {
        let mut ab = Bytes::copy_from_slice(b"ab");
        let mut cd = Bytes::copy_from_slice(b"cd");
        let mut chain = (&mut ab).chain(&mut cd);
        assert_eq!(Bytes::copy_from_slice(b"abcd"), chain.to_bytes());
        assert_eq!(Bytes::new(), ab);
        assert_eq!(Bytes::new(), cd);
    }

    #[test]
    fn chain_to_bytes_first_empty() {
        let mut cd = Bytes::copy_from_slice(b"cd");
        let cd_ptr = cd.as_ptr();
        let mut chain = Bytes::new().chain(&mut cd);
        let cd_to_bytes = chain.to_bytes();
        assert_eq!(b"cd", cd_to_bytes.as_ref());
        // assert `to_bytes` did not allocate
        // this is not possible without reimplementing `to_bytes` in `Chain`
        // assert_eq!(cd_ptr, cd_to_bytes.as_ptr());
        // assert_eq!(Bytes::new(), cd);
    }

    #[test]
    fn chain_to_bytes_second_empty() {
        let mut ab = Bytes::copy_from_slice(b"ab");
        let ab_ptr = ab.as_ptr();
        let mut chain = (&mut ab).chain(Bytes::new());
        let ab_to_bytes = chain.to_bytes();
        assert_eq!(b"ab", ab_to_bytes.as_ref());
        // assert `to_bytes` did not allocate
        // this is not possible without reimplementing `to_bytes` in `Chain`
        // assert_eq!(ab_ptr, ab_to_bytes.as_ptr());
        // assert_eq!(Bytes::new(), ab);
    }

    #[test]
    fn chain_get_bytes() {
        let mut ab = Bytes::copy_from_slice(b"ab");
        let mut cd = Bytes::copy_from_slice(b"cd");
        let ab_ptr = ab.as_ptr();
        let cd_ptr = cd.as_ptr();
        let mut chain = (&mut ab).chain(&mut cd);
        let a = chain.get_bytes(1);
        let bc = chain.get_bytes(2);
        let d = chain.get_bytes(1);

        assert_eq!(Bytes::copy_from_slice(b"a"), a);
        assert_eq!(Bytes::copy_from_slice(b"bc"), bc);
        assert_eq!(Bytes::copy_from_slice(b"d"), d);

        // assert `get_bytes` did not allocate
        assert_eq!(ab_ptr, a.as_ptr());
        // assert `get_bytes` did not allocate
        assert_eq!(cd_ptr.wrapping_offset(1), d.as_ptr());
    }

    #[test]
    fn take_to_bytes() {
        let mut abcd = Bytes::copy_from_slice(b"abcd");
        let abcd_ptr = abcd.as_ptr();
        let mut take = (&mut abcd).take(2);
        let ab = take.to_bytes();
        assert_eq!(Bytes::copy_from_slice(b"ab"), ab);
        // assert `to_bytes` did not allocate
        // this is not possible without reimplementing `to_bytes` in `Take`
        //assert_eq!(abcd_ptr, ab.as_ptr());
        //assert_eq!(Bytes::copy_from_slice(b"cd"), abcd);
    }

    #[test]
    fn take_get_bytes() {
        let mut abcd = Bytes::copy_from_slice(b"abcd");
        let abcd_ptr = abcd.as_ptr();
        let mut take = (&mut abcd).take(2);
        let a = take.get_bytes(1);
        assert_eq!(Bytes::copy_from_slice(b"a"), a);
        // assert `to_bytes` did not allocate
        assert_eq!(abcd_ptr, a.as_ptr());
        assert_eq!(Bytes::copy_from_slice(b"bcd"), abcd);
    }

    #[test]
    #[should_panic]
    fn take_get_bytes_panics() {
        let abcd = Bytes::copy_from_slice(b"abcd");
        abcd.take(2).get_bytes(3);
    }
}
<commit_msg>Warnings<commit_after>//! Implementation of `get_bytes` operation on `Buf`.
//!
//! See also [this PR](https://github.com/tokio-rs/bytes/pull/363).

use bytes::buf::ext::BufExt;
use bytes::buf::ext::Chain;
use bytes::buf::ext::Take;
use bytes::Buf;
use bytes::BufMut;
use bytes::Bytes;
use bytes::BytesMut;
use std::cmp;
use std::io::Cursor;

/// Get `Bytes` from `Buf`.
pub trait BufGetBytes: Buf {
    /// Consumes requested number of bytes from `self`.
    ///
    /// # Examples
    ///
    /// ```
    /// use bytes::Buf;
    /// use httpbis::BufGetBytes;
    ///
    /// let bytes = (&b"hello world"[..]).get_bytes(5);
    /// assert_eq!(&bytes[..], &b"hello"[..]);
    /// ```
    ///
    /// # Panics
    ///
    /// This function panics if there is not enough remaining data in `self`.
    fn get_bytes(&mut self, mut cnt: usize) -> Bytes {
        if cnt == 0 {
            return Bytes::new();
        }

        assert!(self.remaining() >= cnt);

        // Could be as simple as self.take(count).to_bytes()
        // but compiler stack overflows on instantiation of test Buf impl for some types

        let mut ret = BytesMut::with_capacity(cnt);

        while cnt != 0 {
            let bytes = self.bytes();
            let step = cmp::min(bytes.len(), cnt);
            ret.put_slice(&bytes[..step]);
            self.advance(step);
            cnt -= step;
        }

        ret.freeze()
    }
}

impl BufGetBytes for Bytes {
    fn get_bytes(&mut self, cnt: usize) -> Bytes {
        self.split_to(cnt)
    }
}

impl BufGetBytes for BytesMut {
    fn get_bytes(&mut self, cnt: usize) -> Bytes {
        self.split_to(cnt).freeze()
    }
}

impl BufGetBytes for &[u8] {}

impl<A: AsRef<[u8]>> BufGetBytes for Cursor<A> {}

impl<A: BufGetBytes, B: BufGetBytes> BufGetBytes for Chain<A, B> {
    fn get_bytes(&mut self, cnt: usize) -> Bytes {
        let a_rem = self.first_mut().remaining();
        if a_rem >= cnt {
            self.first_mut().get_bytes(cnt)
        } else if !self.first_mut().has_remaining() {
            self.last_mut().get_bytes(cnt)
        } else {
            assert!(cnt <= a_rem + self.last_mut().remaining());

            let mut ret = BytesMut::with_capacity(cnt);
            ret.put(self.first_mut());
            ret.put((self.last_mut()).take(cnt - a_rem));
            ret.freeze()
        }
    }
}

impl<A: BufGetBytes> BufGetBytes for Take<A> {
    fn get_bytes(&mut self, cnt: usize) -> Bytes {
        assert!(cnt <= self.remaining());
        let ret = self.get_mut().get_bytes(cnt);
        self.set_limit(self.limit() - cnt);
        ret
    }
}

impl<A: BufGetBytes> BufGetBytes for &mut A {
    fn get_bytes(&mut self, cnt: usize) -> Bytes {
        (&mut **self).get_bytes(cnt)
    }
}

#[cfg(test)]
mod test {
    use crate::bytes_ext::buf_get_bytes::BufGetBytes;
    use bytes::buf::BufExt;
    use bytes::Buf;
    use bytes::Bytes;
    use bytes::BytesMut;

    #[test]
    fn get_to_bytes() {
        let mut buf = &b"abcd"[..];
        assert_eq!(Bytes::copy_from_slice(b"abcd"), buf.to_bytes());
        assert_eq!(b"", buf);
    }

    #[test]
    fn get_get_bytes() {
        let mut buf = &b"abcd"[..];
        assert_eq!(Bytes::copy_from_slice(b"abc"), buf.get_bytes(3));
        assert_eq!(b"d", buf);
    }

    #[test]
    fn bytes_get_bytes() {
        let mut bytes = Bytes::from(b"abc".to_vec());

        let a = bytes.get_bytes(1);
        assert_eq!(b"a", a.as_ref());
        // assert returned bytes object is a subslice of original bytes object
        assert_eq!(
            a.as_ref().as_ptr() as usize + 1,
            bytes.as_ref().as_ptr() as usize
        );

        let bc = bytes.get_bytes(2);
        assert_eq!(b"bc", bc.as_ref());
        // assert returned bytes object is a subslice of original bytes object
        assert_eq!(
            bc.as_ref().as_ptr() as usize,
            a.as_ref().as_ptr() as usize + 1
        );

        assert_eq!(Bytes::new(), bytes);
    }

    #[test]
    fn bytes_mut_get_bytes() {
        let mut bytes = BytesMut::from(&b"abc"[..]);

        let a = bytes.get_bytes(1);
        assert_eq!(b"a", a.as_ref());
        // assert returned bytes object is a subslice of original bytes object
        assert_eq!(
            a.as_ref().as_ptr() as usize + 1,
            bytes.as_ref().as_ptr() as usize
        );

        let bc = bytes.get_bytes(2);
        assert_eq!(b"bc", bc.as_ref());
        // assert returned bytes object is a subslice of original bytes object
        assert_eq!(
            bc.as_ref().as_ptr() as usize,
            a.as_ref().as_ptr() as usize + 1
        );

        assert_eq!(BytesMut::new(), bytes);
    }

    #[test]
    fn chain_to_bytes() {
        let mut ab = Bytes::copy_from_slice(b"ab");
        let mut cd = Bytes::copy_from_slice(b"cd");
        let mut chain = (&mut ab).chain(&mut cd);
        assert_eq!(Bytes::copy_from_slice(b"abcd"), chain.to_bytes());
        assert_eq!(Bytes::new(), ab);
        assert_eq!(Bytes::new(), cd);
    }

    #[test]
    fn chain_to_bytes_first_empty() {
        let mut cd = Bytes::copy_from_slice(b"cd");
        let cd_ptr = cd.as_ptr();
        let mut chain = Bytes::new().chain(&mut cd);
        let cd_to_bytes = chain.to_bytes();
        assert_eq!(b"cd", cd_to_bytes.as_ref());
        // assert `to_bytes` did not allocate
        // this is not possible without reimplementing `to_bytes` in `Chain`
        // assert_eq!(cd_ptr, cd_to_bytes.as_ptr());
        // assert_eq!(Bytes::new(), cd);
    }

    #[test]
    fn chain_to_bytes_second_empty() {
        let mut ab = Bytes::copy_from_slice(b"ab");
        let ab_ptr = ab.as_ptr();
        let mut chain = (&mut ab).chain(Bytes::new());
        let ab_to_bytes = chain.to_bytes();
        assert_eq!(b"ab", ab_to_bytes.as_ref());
        // assert `to_bytes` did not allocate
        // this is not possible without reimplementing `to_bytes` in `Chain`
        // assert_eq!(ab_ptr, ab_to_bytes.as_ptr());
        // assert_eq!(Bytes::new(), ab);
    }

    #[test]
    fn chain_get_bytes() {
        let mut ab = Bytes::copy_from_slice(b"ab");
        let mut cd = Bytes::copy_from_slice(b"cd");
        let ab_ptr = ab.as_ptr();
        let cd_ptr = cd.as_ptr();
        let mut chain = (&mut ab).chain(&mut cd);
        let a = chain.get_bytes(1);
        let bc = chain.get_bytes(2);
        let d = chain.get_bytes(1);

        assert_eq!(Bytes::copy_from_slice(b"a"), a);
        assert_eq!(Bytes::copy_from_slice(b"bc"), bc);
        assert_eq!(Bytes::copy_from_slice(b"d"), d);

        // assert `get_bytes` did not allocate
        assert_eq!(ab_ptr, a.as_ptr());
        // assert `get_bytes` did not allocate
        assert_eq!(cd_ptr.wrapping_offset(1), d.as_ptr());
    }

    #[test]
    fn take_to_bytes() {
        let mut abcd = Bytes::copy_from_slice(b"abcd");
        let abcd_ptr = abcd.as_ptr();
        let mut take = (&mut abcd).take(2);
        let ab = take.to_bytes();
        assert_eq!(Bytes::copy_from_slice(b"ab"), ab);
        // assert `to_bytes` did not allocate
        // this is not possible without reimplementing `to_bytes` in `Take`
        //assert_eq!(abcd_ptr, ab.as_ptr());
        //assert_eq!(Bytes::copy_from_slice(b"cd"), abcd);
    }

    #[test]
    fn take_get_bytes() {
        let mut abcd = Bytes::copy_from_slice(b"abcd");
        let abcd_ptr = abcd.as_ptr();
        let mut take = (&mut abcd).take(2);
        let a = take.get_bytes(1);
        assert_eq!(Bytes::copy_from_slice(b"a"), a);
        // assert `to_bytes` did not allocate
        assert_eq!(abcd_ptr, a.as_ptr());
        assert_eq!(Bytes::copy_from_slice(b"bcd"), abcd);
    }

    #[test]
    #[should_panic]
    fn take_get_bytes_panics() {
        let abcd = Bytes::copy_from_slice(b"abcd");
        abcd.take(2).get_bytes(3);
    }
}
<|endoftext|>


<commit_before>use players::*;
use std::path::Path;

use std::time::*;
use std::fs;

use glob::*;

pub struct MctsPlayer {
    mcts_m  : mcts::MctsTree<CoinNet>,
    rounds  : usize,
}

impl MctsPlayer {
    pub fn new(_s : Turn, model_path : &Path, params_path : &Path, rounds : usize) -> MctsPlayer {

        let tmp_dir = &Path::new("/tmp/coin_othello/");
        fs::create_dir_all(tmp_dir).unwrap();

        let model_filename = model_path.file_name().expect("Error getting graph file name.");

        fs::copy(model_path, tmp_dir.join(model_filename)).unwrap();
        let glob_path = format!("{}*", params_path.display());
        for path in glob(&glob_path).expect("Failed to find parameter files.") {
            if let Ok(path) = path {
                fs::copy(path.clone(), tmp_dir.join(path.file_name().unwrap())).unwrap();
            }
        }

        let mut net = CoinNet::new(model_path).unwrap();
        net.load(params_path).unwrap();

        let mut mcts_m = MctsTree::new(net);
        mcts_m.set_temp(1.0);
        MctsPlayer {
            mcts_m,
            rounds,
        }
    }
}

impl Player for MctsPlayer {

    fn do_move(&mut self, b : Board, mut ms_left : u64) -> Move {
        let pieces = b.count_pieces();
        let total = pieces.0 + pieces.1;
        let empty = (64 - total) as u64;

        let solve_depth = 20;

        let ttime = Instant::now();
        let mut start = Instant::now();

        let mut moves = empty_movelist();
        let n = b.get_moves(&mut moves) as usize;

        eprintln!("[COIN] {} nodes in the tree.", self.mcts_m.count_sims());

        eprintln!("[COIN] {} ms remaining.", ms_left);

        let pruned = self.mcts_m.prune_board(b.clone());

        eprintln!("[COIN] Saved {} Nodes.", pruned);

        let mut timeout = false;

        let mut out_move = Move::null();

        if empty < solve_depth {
            eprintln!("[COIN] Attempting to solve the game.");
            let (m,s) = self.mcts_m.solve_endgame(start, Duration::from_millis(ms_left/4), &mut timeout);

            ms_left *= 3;
            ms_left /= 4;

            if timeout {
                eprintln!("[COIN] Timeout on endgame solver, researching with MCTS.");
                start = Instant::now();
            } else {
                out_move = m;
                eprintln!("[COIN] Solved game! Result: {} {}", s, m);
            }
        }

        let alloc_time = (ms_left as f32 * TIME_ALLOC[total as usize]) as u64;

        if timeout || empty >= solve_depth {
            eprintln!("[COIN] Searching...");
            //let expansions = self.mcts_m.time_rounds(alloc_time);
            let expansions = self.rounds; self.mcts_m.n_rounds(self.rounds);
            eprintln!("[COIN] Done!");
            eprintln!("[COIN] Generated {} Nodes. ({} n/s)", expansions, expansions as f32 * 1000.0 / alloc_time as f32);

            let EvalOutput(output, score) = self.mcts_m.evaluate(&Board::new());
            eprintln!("[COIN] Score={:.3}", score);

            eprint!("[COIN] Main Line:");
            let main_line = self.mcts_m.scan(4);

            for mv in main_line {
                eprint!(" {}", mv);
            }
            eprintln!("...");

            let mut mi = 0;
            let mut mx = output[moves[0].offset() as usize];

            for i in 1..n {
                let tmp = output[moves[i].offset() as usize];
                if mx < tmp {
                    mx = tmp;
                    mi = i;
                }
            }

            out_move = moves[mi];
        }

        if out_move.is_null() {
            eprintln!("[COIN] Something went wrong. Choosing random move.");
            let mut ml = empty_movelist();
            let n = b.get_moves(&mut ml) as usize;

            use rand;
            use rand::Rng;
            out_move = ml[rand::thread_rng().gen::<usize>()%n];
        }

        let self_pruned = self.mcts_m.prune(out_move);

        eprintln!("[COIN] Playing {} ({} nodes remaining)", out_move, self_pruned);

        let elapsed_time = {
            let e = ttime.elapsed();
            let s = e.as_secs();
            let ns = e.subsec_nanos();

            s * 1000 + ns as u64 / 1_000_000
        };

        eprintln!("[COIN] Turn took {} ms.", elapsed_time);

        out_move
    }
}
<commit_msg>fixed a bug in the tmp file copying code<commit_after>use players::*;
use std::path::Path;

use std::time::*;
use std::fs;

use glob::*;

pub struct MctsPlayer {
    mcts_m  : mcts::MctsTree<CoinNet>,
    rounds  : usize,
}

impl MctsPlayer {
    pub fn new(_s : Turn, model_path : &Path, params_path : &Path, rounds : usize) -> MctsPlayer {

        let tmp_dir = &Path::new("/tmp/coin_othello/");
        fs::create_dir_all(tmp_dir).unwrap();

        let model_filename = model_path.file_name().expect("Error getting graph file name.");
        let params_filename = params_path.file_name().expect("Error getting graph file name.");

        fs::copy(model_path, tmp_dir.join(model_filename)).unwrap();
        let glob_path = format!("{}*", params_path.display());
        for path in glob(&glob_path).expect("Failed to find parameter files.") {
            if let Ok(path) = path {
                fs::copy(path.clone(), tmp_dir.join(path.file_name().unwrap())).unwrap();
            }
        }

        let model_path = &tmp_dir.join(model_filename);
        let params_path = &tmp_dir.join(params_filename);

        let mut net = CoinNet::new(model_path).unwrap();
        net.load(params_path).unwrap();

        let mut mcts_m = MctsTree::new(net);
        mcts_m.set_temp(1.0);
        MctsPlayer {
            mcts_m,
            rounds,
        }
    }
}

impl Player for MctsPlayer {

    fn do_move(&mut self, b : Board, mut ms_left : u64) -> Move {
        let pieces = b.count_pieces();
        let total = pieces.0 + pieces.1;
        let empty = (64 - total) as u64;

        let solve_depth = 20;

        let ttime = Instant::now();
        let mut start = Instant::now();

        let mut moves = empty_movelist();
        let n = b.get_moves(&mut moves) as usize;

        eprintln!("[COIN] {} nodes in the tree.", self.mcts_m.count_sims());

        eprintln!("[COIN] {} ms remaining.", ms_left);

        let pruned = self.mcts_m.prune_board(b.clone());

        eprintln!("[COIN] Saved {} Nodes.", pruned);

        let mut timeout = false;

        let mut out_move = Move::null();

        if empty < solve_depth {
            eprintln!("[COIN] Attempting to solve the game.");
            let (m,s) = self.mcts_m.solve_endgame(start, Duration::from_millis(ms_left/4), &mut timeout);

            ms_left *= 3;
            ms_left /= 4;

            if timeout {
                eprintln!("[COIN] Timeout on endgame solver, researching with MCTS.");
                start = Instant::now();
            } else {
                out_move = m;
                eprintln!("[COIN] Solved game! Result: {} {}", s, m);
            }
        }

        let alloc_time = (ms_left as f32 * TIME_ALLOC[total as usize]) as u64;

        if timeout || empty >= solve_depth {
            eprintln!("[COIN] Searching...");
            //let expansions = self.mcts_m.time_rounds(alloc_time);
            let expansions = self.rounds; self.mcts_m.n_rounds(self.rounds);
            eprintln!("[COIN] Done!");
            eprintln!("[COIN] Generated {} Nodes. ({} n/s)", expansions, expansions as f32 * 1000.0 / alloc_time as f32);

            let EvalOutput(output, score) = self.mcts_m.evaluate(&Board::new());
            eprintln!("[COIN] Score={:.3}", score);

            eprint!("[COIN] Main Line:");
            let main_line = self.mcts_m.scan(4);

            for mv in main_line {
                eprint!(" {}", mv);
            }
            eprintln!("...");

            let mut mi = 0;
            let mut mx = output[moves[0].offset() as usize];

            for i in 1..n {
                let tmp = output[moves[i].offset() as usize];
                if mx < tmp {
                    mx = tmp;
                    mi = i;
                }
            }

            out_move = moves[mi];
        }

        if out_move.is_null() {
            eprintln!("[COIN] Something went wrong. Choosing random move.");
            let mut ml = empty_movelist();
            let n = b.get_moves(&mut ml) as usize;

            use rand;
            use rand::Rng;
            out_move = ml[rand::thread_rng().gen::<usize>()%n];
        }

        let self_pruned = self.mcts_m.prune(out_move);

        eprintln!("[COIN] Playing {} ({} nodes remaining)", out_move, self_pruned);

        let elapsed_time = {
            let e = ttime.elapsed();
            let s = e.as_secs();
            let ns = e.subsec_nanos();

            s * 1000 + ns as u64 / 1_000_000
        };

        eprintln!("[COIN] Turn took {} ms.", elapsed_time);

        out_move
    }
}
<|endoftext|>


<commit_before>use json::JsonValue;
use std::path::PathBuf;

use crate::d3dmesh::d3dfile::D3DFile;

pub fn empty_gltf() -> json::JsonValue {
    let asset = json::object! {
        generator: "telltale-converter",
        version: "2.0"
    };

    let mut gltf = json::object! {
        asset: asset,
    };

    gltf
}

pub fn add_mesh_to_gltf(mesh: &D3DFile, gltf: &mut JsonValue) {
    let _ = crate::gltf::get_scene_0_mut(gltf);

    let indices = mesh.get_buffer("index").unwrap();
    let buffer = indices.as_u16().as_slice();
    let mut indices_buffer_view = crate::gltf::push_buffer(gltf, buffer);
    indices_buffer_view["target"] = json::JsonValue::Number(34963i32.into());
    let indices_buffer_view_idx = crate::gltf::push_buffer_view(gltf, indices_buffer_view);

    let pos_acessor = if let Some(vertices) = mesh.get_buffer("position") {
        let vertices = vertices.as_f32().as_slice();
        let mut vertices_buffer_view = crate::gltf::push_buffer(gltf, vertices);
        vertices_buffer_view["target"] = json::JsonValue::Number(34962i32.into());
        let vertices_buffer_view_idx = crate::gltf::push_buffer_view(gltf, vertices_buffer_view);
        Some(crate::gltf::push_accessor(
            gltf,
            json::object! {
                bufferView: vertices_buffer_view_idx,
                componentType: 5126,
                count: vertices.len() / 3,
                type: "VEC3",
                byteOffset: 0,
            },
        ))
    } else {
        None
    };

    let mut uvs_acessors = vec![];

    // albedo uvs
    uvs_acessors.extend(push_texture_coordinate(mesh, 0, gltf));
    uvs_acessors.extend(push_texture_coordinate(mesh, 1, gltf));

    dbg!(&uvs_acessors);

    let sampler_idx = crate::gltf::push_sampler(
        gltf,
        json::object! {
            magFilter: 9729,
            minFilter: 9987,
            wrapS: 33648,
            wrapT: 33648
        },
    );

    let mesh_idx = crate::gltf::push_mesh(
        gltf,
        json::object! {
            primitives : []
        },
    );

    let node_idx = crate::gltf::push_node(
        gltf,
        json::object! {
            mesh: mesh_idx,
        },
    );

    let scene = crate::gltf::get_scene_0_mut(gltf);
    let _ = scene["nodes"].push(node_idx);

    for (_, m) in mesh.meshes.iter().enumerate() {
        let start = m.index_start;
        let end = start + (m.tri_count * 3);

        let indices_acessor_idx = crate::gltf::push_accessor(
            gltf,
            json::object! {
                bufferView: indices_buffer_view_idx,
                byteOffset: start * 2,
                componentType: 5123,
                count: end - start,
                type: "SCALAR",
            },
        );

        let _ = gltf["meshes"][mesh_idx]["primitives"].push(json::object! {
            attributes: {
                POSITION: pos_acessor
            },
            indices: indices_acessor_idx
        });
        let primitive_id = gltf["meshes"][mesh_idx]["primitives"].len() - 1;

        let material_idx = crate::gltf::push_material(
            gltf,
            json::object! {
                pbrMetallicRoughness: {
                    metallicFactor: 0.0,
                    roughnessFactor: 1.0,
                }
            },
        );

        for (i, uv) in uvs_acessors.iter().enumerate() {
            let map = match m.maps.get(i) {
                Some(map) => map,
                None => continue,
            };

            let texcoordi = format!("TEXCOORD_{i}");

            gltf["meshes"][mesh_idx]["primitives"][primitive_id]["attributes"][texcoordi] =
                JsonValue::Number((*uv).into());

            let image_idx = crate::gltf::push_image(
                gltf,
                json::object! {
                    uri: map.name.as_str()
                },
            );

            let texture_idx = crate::gltf::push_texture(
                gltf,
                json::object! {
                    sampler: sampler_idx,
                    source: image_idx
                },
            );

            match map.r#type.as_str() {
                "albedo" => {
                    gltf["materials"][material_idx]["pbrMetallicRoughness"]["baseColorTexture"] = json::object! {
                        index: texture_idx,
                        texCoord: i
                    };
                }
                "occlusion" => {
                    gltf["materials"][material_idx]["occlusionTexture"] = json::object! {
                        index: texture_idx,
                        texCoord: i
                    };
                }
                _ => {}
            }
        }

        gltf["meshes"][mesh_idx]["primitives"][primitive_id]["material"] =
            JsonValue::Number(material_idx.into());
    }

    // if let Some(bone_idx) = mesh.get_buffer("bone_idx") {
    //     let bone_idx = bone_idx.as_u8().as_slice();
    //     let mut bone_idx_view = crate::gltf::push_buffer(gltf, bone_idx);
    //     bone_idx_view["target"] = json::JsonValue::Number(34962i32.into());
    //     let bone_idx_view_idx = crate::gltf::push_buffer_view(gltf, bone_idx_view);
    //     let bone_idx_acessor_idx = crate::gltf::push_accessor(
    //         gltf,
    //         json::object! {
    //             bufferView: bone_idx_view_idx,
    //             componentType: 5121,
    //             count: bone_idx.len() / 4,
    //             type: "VEC4",
    //             byteOffset: 0,
    //         },
    //     );
    //     primitive["attributes"].insert("JOINTS_0", JsonValue::Number(bone_idx_acessor_idx.into()));
    // }

    // if let Some(bone_weights) = mesh.get_buffer("bone_weigth") {
    //     let bone_weights = bone_weights.as_f32().as_slice();
    //     let mut bone_weights_view = crate::gltf::push_buffer(gltf, bone_weights);
    //     bone_weights_view["target"] = json::JsonValue::Number(34962i32.into());
    //     let bone_weights_view_idx = crate::gltf::push_buffer_view(gltf, bone_weights_view);
    //     let bone_weights_acessor_idx = crate::gltf::push_accessor(
    //         gltf,
    //         json::object! {
    //             bufferView: bone_weights_view_idx,
    //             componentType: 5126,
    //             count: bone_weights.len() / 4,
    //             type: "VEC4",
    //             byteOffset: 0,
    //         },
    //     );
    //     primitive["attributes"].insert(
    //         "WEIGHTS_0",
    //         JsonValue::Number(bone_weights_acessor_idx.into()),
    //     );
    // }

    // crate::gltf::push_mesh(
    //     gltf,
    //     json::object! {
    //         primitives : [primitive]
    //     },
    // );

    // crate::gltf::push_scene(
    //     gltf,
    //     json::object! {
    //          nodes: [0]
    //     },
    // );

    // crate::gltf::push_node(
    //     gltf,
    //     json::object! {
    //         mesh: 0,
    //     },
    // );
}

fn push_texture_coordinate(mesh: &D3DFile, idx: usize, gltf: &mut JsonValue) -> Option<usize> {
    if let Some(uvs) = mesh.nth_buffer(idx, "texcoords") {
        let uvs = uvs.as_f32().as_slice();
        let mut uvs_buffer_view = crate::gltf::push_buffer(gltf, uvs);
        uvs_buffer_view["target"] = json::JsonValue::Number(34962i32.into());
        let uvs_buffer_view_idx = crate::gltf::push_buffer_view(gltf, uvs_buffer_view);
        let uvs_acessor_idx = crate::gltf::push_accessor(
            gltf,
            json::object! {
                bufferView: uvs_buffer_view_idx,
                componentType: 5126,
                count: uvs.len() / 2,
                type: "VEC2",
                byteOffset: 0,
            },
        );

        Some(uvs_acessor_idx)
    } else {
        None
    }
}

pub fn save_to_gltf(mesh: &D3DFile, output: PathBuf) {
    let mut gltf = empty_gltf();
    add_mesh_to_gltf(mesh, &mut gltf);

    crate::skl::gltf::save(output, &gltf);
}
<commit_msg>avoid duplication of images<commit_after>use json::JsonValue;
use std::{collections::HashMap, path::PathBuf};

use crate::d3dmesh::d3dfile::D3DFile;

pub fn empty_gltf() -> json::JsonValue {
    let asset = json::object! {
        generator: "telltale-converter",
        version: "2.0"
    };

    let mut gltf = json::object! {
        asset: asset,
    };

    gltf
}

pub fn add_mesh_to_gltf(mesh: &D3DFile, gltf: &mut JsonValue) {
    let _ = crate::gltf::get_scene_0_mut(gltf);

    let indices = mesh.get_buffer("index").unwrap();
    let buffer = indices.as_u16().as_slice();
    let mut indices_buffer_view = crate::gltf::push_buffer(gltf, buffer);
    indices_buffer_view["target"] = json::JsonValue::Number(34963i32.into());
    let indices_buffer_view_idx = crate::gltf::push_buffer_view(gltf, indices_buffer_view);

    let pos_acessor = if let Some(vertices) = mesh.get_buffer("position") {
        let vertices = vertices.as_f32().as_slice();
        let mut vertices_buffer_view = crate::gltf::push_buffer(gltf, vertices);
        vertices_buffer_view["target"] = json::JsonValue::Number(34962i32.into());
        let vertices_buffer_view_idx = crate::gltf::push_buffer_view(gltf, vertices_buffer_view);
        Some(crate::gltf::push_accessor(
            gltf,
            json::object! {
                bufferView: vertices_buffer_view_idx,
                componentType: 5126,
                count: vertices.len() / 3,
                type: "VEC3",
                byteOffset: 0,
            },
        ))
    } else {
        None
    };

    let mut uvs_acessors = vec![];

    // albedo uvs
    uvs_acessors.extend(push_texture_coordinate(mesh, 0, gltf));
    uvs_acessors.extend(push_texture_coordinate(mesh, 1, gltf));

    let mut image_idxs = HashMap::new();

    let sampler_idx = crate::gltf::push_sampler(
        gltf,
        json::object! {
            magFilter: 9729,
            minFilter: 9987,
            wrapS: 33648,
            wrapT: 33648
        },
    );

    let mesh_idx = crate::gltf::push_mesh(
        gltf,
        json::object! {
            primitives : []
        },
    );

    let node_idx = crate::gltf::push_node(
        gltf,
        json::object! {
            mesh: mesh_idx,
        },
    );

    let scene = crate::gltf::get_scene_0_mut(gltf);
    let _ = scene["nodes"].push(node_idx);

    for (_, m) in mesh.meshes.iter().enumerate() {
        let start = m.index_start;
        let end = start + (m.tri_count * 3);

        let indices_acessor_idx = crate::gltf::push_accessor(
            gltf,
            json::object! {
                bufferView: indices_buffer_view_idx,
                byteOffset: start * 2,
                componentType: 5123,
                count: end - start,
                type: "SCALAR",
            },
        );

        let _ = gltf["meshes"][mesh_idx]["primitives"].push(json::object! {
            attributes: {
                POSITION: pos_acessor
            },
            indices: indices_acessor_idx
        });
        let primitive_id = gltf["meshes"][mesh_idx]["primitives"].len() - 1;

        let material_idx = crate::gltf::push_material(
            gltf,
            json::object! {
                pbrMetallicRoughness: {
                    metallicFactor: 0.0,
                    roughnessFactor: 1.0,
                }
            },
        );

        for (i, uv) in uvs_acessors.iter().enumerate() {
            let map = match m.maps.get(i) {
                Some(map) => map,
                None => continue,
            };

            let texcoordi = format!("TEXCOORD_{i}");

            gltf["meshes"][mesh_idx]["primitives"][primitive_id]["attributes"][texcoordi] =
                JsonValue::Number((*uv).into());

            let image_idx = if let Some(image_idx) = image_idxs.get(&map.name) {
                *image_idx
            } else {
                let image_idx = crate::gltf::push_image(
                    gltf,
                    json::object! {
                        uri: map.name.as_str()
                    },
                );
                image_idxs.insert(map.name.clone(), image_idx);
                image_idx
            };

            let texture_idx = crate::gltf::push_texture(
                gltf,
                json::object! {
                    sampler: sampler_idx,
                    source: image_idx
                },
            );

            match map.r#type.as_str() {
                "albedo" => {
                    gltf["materials"][material_idx]["pbrMetallicRoughness"]["baseColorTexture"] = json::object! {
                        index: texture_idx,
                        texCoord: i
                    };
                }
                "occlusion" => {
                    gltf["materials"][material_idx]["occlusionTexture"] = json::object! {
                        index: texture_idx,
                        texCoord: i
                    };
                }
                _ => {}
            }
        }

        gltf["meshes"][mesh_idx]["primitives"][primitive_id]["material"] =
            JsonValue::Number(material_idx.into());
    }

    // if let Some(bone_idx) = mesh.get_buffer("bone_idx") {
    //     let bone_idx = bone_idx.as_u8().as_slice();
    //     let mut bone_idx_view = crate::gltf::push_buffer(gltf, bone_idx);
    //     bone_idx_view["target"] = json::JsonValue::Number(34962i32.into());
    //     let bone_idx_view_idx = crate::gltf::push_buffer_view(gltf, bone_idx_view);
    //     let bone_idx_acessor_idx = crate::gltf::push_accessor(
    //         gltf,
    //         json::object! {
    //             bufferView: bone_idx_view_idx,
    //             componentType: 5121,
    //             count: bone_idx.len() / 4,
    //             type: "VEC4",
    //             byteOffset: 0,
    //         },
    //     );
    //     primitive["attributes"].insert("JOINTS_0", JsonValue::Number(bone_idx_acessor_idx.into()));
    // }

    // if let Some(bone_weights) = mesh.get_buffer("bone_weigth") {
    //     let bone_weights = bone_weights.as_f32().as_slice();
    //     let mut bone_weights_view = crate::gltf::push_buffer(gltf, bone_weights);
    //     bone_weights_view["target"] = json::JsonValue::Number(34962i32.into());
    //     let bone_weights_view_idx = crate::gltf::push_buffer_view(gltf, bone_weights_view);
    //     let bone_weights_acessor_idx = crate::gltf::push_accessor(
    //         gltf,
    //         json::object! {
    //             bufferView: bone_weights_view_idx,
    //             componentType: 5126,
    //             count: bone_weights.len() / 4,
    //             type: "VEC4",
    //             byteOffset: 0,
    //         },
    //     );
    //     primitive["attributes"].insert(
    //         "WEIGHTS_0",
    //         JsonValue::Number(bone_weights_acessor_idx.into()),
    //     );
    // }

    // crate::gltf::push_mesh(
    //     gltf,
    //     json::object! {
    //         primitives : [primitive]
    //     },
    // );

    // crate::gltf::push_scene(
    //     gltf,
    //     json::object! {
    //          nodes: [0]
    //     },
    // );

    // crate::gltf::push_node(
    //     gltf,
    //     json::object! {
    //         mesh: 0,
    //     },
    // );
}

fn push_texture_coordinate(mesh: &D3DFile, idx: usize, gltf: &mut JsonValue) -> Option<usize> {
    if let Some(uvs) = mesh.nth_buffer(idx, "texcoords") {
        let uvs = uvs.as_f32().as_slice();
        let mut uvs_buffer_view = crate::gltf::push_buffer(gltf, uvs);
        uvs_buffer_view["target"] = json::JsonValue::Number(34962i32.into());
        let uvs_buffer_view_idx = crate::gltf::push_buffer_view(gltf, uvs_buffer_view);
        let uvs_acessor_idx = crate::gltf::push_accessor(
            gltf,
            json::object! {
                bufferView: uvs_buffer_view_idx,
                componentType: 5126,
                count: uvs.len() / 2,
                type: "VEC2",
                byteOffset: 0,
            },
        );

        Some(uvs_acessor_idx)
    } else {
        None
    }
}

pub fn save_to_gltf(mesh: &D3DFile, output: PathBuf) {
    let mut gltf = empty_gltf();
    add_mesh_to_gltf(mesh, &mut gltf);

    crate::skl::gltf::save(output, &gltf);
}
<|endoftext|>


<commit_before>use core::cmp::{self};
use core::mem::replace;

use crate::alloc::Allocator;

use super::VecDeque;

/// PairSlices pairs up equal length slice parts of two deques
///
/// For example, given deques "A" and "B" with the following division into slices:
///
/// A: [0 1 2] [3 4 5]
/// B: [a b] [c d e]
///
/// It produces the following sequence of matching slices:
///
/// ([0 1], [a b])
/// (\[2\], \[c\])
/// ([3 4], [d e])
///
/// and the uneven remainder of either A or B is skipped.
pub struct PairSlices<'a, 'b, T> {
    pub(crate) a0: &'a mut [T],
    pub(crate) a1: &'a mut [T],
    pub(crate) b0: &'b [T],
    pub(crate) b1: &'b [T],
}

impl<'a, 'b, T> PairSlices<'a, 'b, T> {
    pub fn from<A: Allocator>(to: &'a mut VecDeque<T, A>, from: &'b VecDeque<T, A>) -> Self {
        let (a0, a1) = to.as_mut_slices();
        let (b0, b1) = from.as_slices();
        PairSlices { a0, a1, b0, b1 }
    }

    pub fn has_remainder(&self) -> bool {
        !self.b0.is_empty()
    }

    pub fn remainder(self) -> impl Iterator<Item = &'b [T]> {
        IntoIterator::into_iter([self.b0, self.b1])
    }
}

impl<'a, 'b, T> Iterator for PairSlices<'a, 'b, T> {
    type Item = (&'a mut [T], &'b [T]);
    fn next(&mut self) -> Option<Self::Item> {
        // Get next part length
        let part = cmp::min(self.a0.len(), self.b0.len());
        if part == 0 {
            return None;
        }
        let (p0, p1) = replace(&mut self.a0, &mut []).split_at_mut(part);
        let (q0, q1) = self.b0.split_at(part);

        // Move a1 into a0, if it's empty (and b1, b0 the same way).
        self.a0 = p1;
        self.b0 = q1;
        if self.a0.is_empty() {
            self.a0 = replace(&mut self.a1, &mut []);
        }
        if self.b0.is_empty() {
            self.b0 = replace(&mut self.b1, &[]);
        }
        Some((p0, q0))
    }
}
<commit_msg>Rollup merge of #89244 - DeveloperC286:pair_slices_fields_to_private, r=joshtriplett<commit_after>use core::cmp::{self};
use core::mem::replace;

use crate::alloc::Allocator;

use super::VecDeque;

/// PairSlices pairs up equal length slice parts of two deques
///
/// For example, given deques "A" and "B" with the following division into slices:
///
/// A: [0 1 2] [3 4 5]
/// B: [a b] [c d e]
///
/// It produces the following sequence of matching slices:
///
/// ([0 1], [a b])
/// (\[2\], \[c\])
/// ([3 4], [d e])
///
/// and the uneven remainder of either A or B is skipped.
pub struct PairSlices<'a, 'b, T> {
    a0: &'a mut [T],
    a1: &'a mut [T],
    b0: &'b [T],
    b1: &'b [T],
}

impl<'a, 'b, T> PairSlices<'a, 'b, T> {
    pub fn from<A: Allocator>(to: &'a mut VecDeque<T, A>, from: &'b VecDeque<T, A>) -> Self {
        let (a0, a1) = to.as_mut_slices();
        let (b0, b1) = from.as_slices();
        PairSlices { a0, a1, b0, b1 }
    }

    pub fn has_remainder(&self) -> bool {
        !self.b0.is_empty()
    }

    pub fn remainder(self) -> impl Iterator<Item = &'b [T]> {
        IntoIterator::into_iter([self.b0, self.b1])
    }
}

impl<'a, 'b, T> Iterator for PairSlices<'a, 'b, T> {
    type Item = (&'a mut [T], &'b [T]);
    fn next(&mut self) -> Option<Self::Item> {
        // Get next part length
        let part = cmp::min(self.a0.len(), self.b0.len());
        if part == 0 {
            return None;
        }
        let (p0, p1) = replace(&mut self.a0, &mut []).split_at_mut(part);
        let (q0, q1) = self.b0.split_at(part);

        // Move a1 into a0, if it's empty (and b1, b0 the same way).
        self.a0 = p1;
        self.b0 = q1;
        if self.a0.is_empty() {
            self.a0 = replace(&mut self.a1, &mut []);
        }
        if self.b0.is_empty() {
            self.b0 = replace(&mut self.b1, &[]);
        }
        Some((p0, q0))
    }
}
<|endoftext|>


<commit_before>//! Low-level bindings to libm

#![cfg(target_os = "linux")]

extern crate linux_api;

use linux_api::{c_double, c_float,
                c_long, c_longlong};

#[link(name = "m")] //For -lm
extern {

    //cos
    //sin
    //tan
    //acos
    //asin
    //atan
    //atan2

    //cosh
    //sinh
    //tanh
    //acosh
    //asinh
    //atanh

    //exp
    //frexp
    //ldexp
    //log
    //log10
    //modf
    //exp2
    //expm1
    //ilogb
    //log1p
    //log2
    //logb
    //scalbn
    //scalbln

    //pow
    //sqrt
    //cbrt
    //hopot

    //erf
    //erfc
    //tgamma
    //lgamma

    //ceil
    //floor
    //fmod
    //trunc
    //round
    //lround
    //llround

    ///Rounds to an integer value in c_double format
    ///
    ///If you want an integer format, use lrint instead
    pub fn rint(x: c_double) -> c_double;

    ///Rounds to an integer value in c_float format
    ///
    ///If you want an integer format, use lrintf instead
    pub fn rintf(x: c_float) -> c_float;

    ///Rounds a c_double to the nearest c_long
    pub fn lrint(x: c_double) -> c_long;

    ///Rounds a c_float to the nearest c_long
    pub fn lrintf(x: c_float) -> c_long;

    ///Rounds a c_double to the nearest c_longlong
    pub fn llrint(x: c_double) -> c_longlong;

    ///Rounds a c_float to the nearest c_longlong
    pub fn llrintf(x: c_float) -> c_longlong;

    ///Rounds to an integer value in c_double format
    ///
    ///If you want an integer format, use lrint instead
    pub fn nearbyint(x: c_double) -> c_double;

    ///Rounds to an integer value in c_float format
    ///
    ///If you want an integer format, use lrintf instead
    pub fn nearbyintf(x: c_float) -> c_float;

    ///Returns the floating-point remainder of numer / denom
    pub fn remainder(numer: c_double, denom: c_double) -> c_double;

    ///Returns the floating-point remainder of numer / denom
    pub fn remainderf(number: c_float, denom: c_float) -> c_float;

    //remquo

    //copysign
    //nan
    //nextafter
    //nexttoward

    //fdim
    //fmax
    //fmin

    //fabs
    //abs
    //fma

}

#[cfg(test)]
#[allow(unused_assignments)] // Unsafe functions
mod test {

    extern crate linux_api;

    use linux_api::{c_long, c_longlong, c_float, c_double};

    use super::*;

    #[test]
    fn test_rint() {

        let value = 246.246f64;

        let mut result = 0f64;

        unsafe { result = rint(value); }

        assert_eq!(246.0f64, result);
    }

    #[test]
    fn test_rintf() {

        let value = 2543637.536f32;

        let mut result = 0f32;

        unsafe { result = rintf(value); }

        assert_eq!(2543638.0f32, result);
    }

    #[test]
    fn test_nearbyint() {

        let value = 246.246f64;

        let mut result = 0f64;

        unsafe { result = nearbyint(value); }

        assert_eq!(246.0f64, result);
    }

    #[test]
    fn test_nearbyintf() {

        let value = 2543637.536f32;

        let mut result = 0f32;

        unsafe { result = nearbyintf(value); }

        assert_eq!(2543638.0f32, result);
    }

    #[test]
    fn test_lrint() {

        let value = 2464326.432f64;

        let mut result: c_long = 0;

        unsafe { result = lrint(value); }

        assert_eq!(2464326, result);

    }

    #[test]
    fn test_lrintf() {

        let value = 2464326.432f32;

        let mut result: c_long = 0;

        unsafe { result = lrintf(value); }

        assert_eq!(2464326, result);

    }

    #[test]
    fn test_llrint() {

        let value = 46873283884.432f64;

        let mut result: c_longlong = 0;

        unsafe { result = llrint(value); }

        assert_eq!(46873283884, result);

    }

    #[test]
    fn test_llrintf() {

        let value = 4687328.9732f32;

        let mut result: c_longlong = 0;

        unsafe { result = llrintf(value); }

        assert_eq!(4687329, result);

    }

    #[test]
    fn test_remainder() {
        let number: c_double = 18.5;
        let denominator: c_double = 4.2;

        unsafe {
            assert!(remainder(number, denominator).abs_sub(1.7) <= 0.0000001);
        }
    }

    #[test]
    fn test_remainderf() {
        let number: c_float = 5.3;
        let denominator: c_float = 2.0;

        unsafe {
            assert!(remainderf(number, denominator).abs_sub(0.7) <= 0.0000001);
        }
    }

}
<commit_msg>Add and test cos and cosf<commit_after>//! Low-level bindings to libm

#![cfg(target_os = "linux")]

extern crate linux_api;

use linux_api::{c_double, c_float,
                c_long, c_longlong};

#[link(name = "m")] //For -lm
extern {

    ///Returns the cosine of an angle of X radians
    pub fn cos(x: c_double) -> c_double;

    ///Returns the cosine of an angle of X radians
    pub fn cosf(x: c_float) -> c_float;

    //sin
    //tan
    //acos
    //asin
    //atan
    //atan2

    //cosh
    //sinh
    //tanh
    //acosh
    //asinh
    //atanh

    //exp
    //frexp
    //ldexp
    //log
    //log10
    //modf
    //exp2
    //expm1
    //ilogb
    //log1p
    //log2
    //logb
    //scalbn
    //scalbln

    //pow
    //sqrt
    //cbrt
    //hopot

    //erf
    //erfc
    //tgamma
    //lgamma

    //ceil
    //floor
    //fmod
    //trunc
    //round
    //lround
    //llround

    ///Rounds to an integer value in c_double format
    ///
    ///If you want an integer format, use lrint instead
    pub fn rint(x: c_double) -> c_double;

    ///Rounds to an integer value in c_float format
    ///
    ///If you want an integer format, use lrintf instead
    pub fn rintf(x: c_float) -> c_float;

    ///Rounds a c_double to the nearest c_long
    pub fn lrint(x: c_double) -> c_long;

    ///Rounds a c_float to the nearest c_long
    pub fn lrintf(x: c_float) -> c_long;

    ///Rounds a c_double to the nearest c_longlong
    pub fn llrint(x: c_double) -> c_longlong;

    ///Rounds a c_float to the nearest c_longlong
    pub fn llrintf(x: c_float) -> c_longlong;

    ///Rounds to an integer value in c_double format
    ///
    ///If you want an integer format, use lrint instead
    pub fn nearbyint(x: c_double) -> c_double;

    ///Rounds to an integer value in c_float format
    ///
    ///If you want an integer format, use lrintf instead
    pub fn nearbyintf(x: c_float) -> c_float;

    ///Returns the floating-point remainder of numer / denom
    pub fn remainder(numer: c_double, denom: c_double) -> c_double;

    ///Returns the floating-point remainder of numer / denom
    pub fn remainderf(number: c_float, denom: c_float) -> c_float;

    //remquo

    //copysign
    //nan
    //nextafter
    //nexttoward

    //fdim
    //fmax
    //fmin

    //fabs
    //abs
    //fma

}

#[cfg(test)]
#[allow(unused_assignments)] // Unsafe functions
mod test {

    extern crate linux_api;

    use linux_api::{c_long, c_longlong, c_float, c_double};

    use super::*;

    #[test]
    fn test_cos() {
        let pi: c_double = 3.14159265;

        let degrees: c_double = 60.0;

        unsafe {
            let result = cos(degrees * pi / 180.0);

            assert!(result.abs_sub(0.5) <= 0.000001);
        }
    }

    #[test]
    fn test_cosf() {
        let pi: c_float = 3.14159265;

        let degrees: c_float = 60.0;

        unsafe {
            let result = cosf(degrees * pi / 180.0);

            assert!(result.abs_sub(0.5) <= 0.000001);
        }
    }

    #[test]
    fn test_rint() {

        let value = 246.246f64;

        let mut result = 0f64;

        unsafe { result = rint(value); }

        assert_eq!(246.0f64, result);
    }

    #[test]
    fn test_rintf() {

        let value = 2543637.536f32;

        let mut result = 0f32;

        unsafe { result = rintf(value); }

        assert_eq!(2543638.0f32, result);
    }

    #[test]
    fn test_nearbyint() {

        let value = 246.246f64;

        let mut result = 0f64;

        unsafe { result = nearbyint(value); }

        assert_eq!(246.0f64, result);
    }

    #[test]
    fn test_nearbyintf() {

        let value = 2543637.536f32;

        let mut result = 0f32;

        unsafe { result = nearbyintf(value); }

        assert_eq!(2543638.0f32, result);
    }

    #[test]
    fn test_lrint() {

        let value = 2464326.432f64;

        let mut result: c_long = 0;

        unsafe { result = lrint(value); }

        assert_eq!(2464326, result);

    }

    #[test]
    fn test_lrintf() {

        let value = 2464326.432f32;

        let mut result: c_long = 0;

        unsafe { result = lrintf(value); }

        assert_eq!(2464326, result);

    }

    #[test]
    fn test_llrint() {

        let value = 46873283884.432f64;

        let mut result: c_longlong = 0;

        unsafe { result = llrint(value); }

        assert_eq!(46873283884, result);

    }

    #[test]
    fn test_llrintf() {

        let value = 4687328.9732f32;

        let mut result: c_longlong = 0;

        unsafe { result = llrintf(value); }

        assert_eq!(4687329, result);

    }

    #[test]
    fn test_remainder() {
        let number: c_double = 18.5;
        let denominator: c_double = 4.2;

        unsafe {
            assert!(remainder(number, denominator).abs_sub(1.7) <= 0.0000001);
        }
    }

    #[test]
    fn test_remainderf() {
        let number: c_float = 5.3;
        let denominator: c_float = 2.0;

        unsafe {
            assert!(remainderf(number, denominator).abs_sub(0.7) <= 0.0000001);
        }
    }

}
<|endoftext|>