<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use api::{ImageDescriptor, ImageDescriptorFlags, DirtyRect};
use api::units::*;
use crate::border::BorderSegmentCacheKey;
use crate::box_shadow::{BoxShadowCacheKey};
use crate::device::TextureFilter;
use crate::freelist::{FreeList, FreeListHandle, WeakFreeListHandle};
use crate::gpu_cache::GpuCache;
use crate::internal_types::FastHashMap;
use crate::picture::{SurfaceIndex, SurfaceInfo};
use crate::prim_store::image::ImageCacheKey;
use crate::prim_store::gradient::{
    FastLinearGradientCacheKey, LinearGradientCacheKey, RadialGradientCacheKey,
    ConicGradientCacheKey,
};
use crate::prim_store::line_dec::LineDecorationCacheKey;
use crate::resource_cache::CacheItem;
use std::{mem, usize, f32, i32};
use crate::texture_cache::{TextureCache, TextureCacheHandle, Eviction, TargetShader};
use crate::render_target::RenderTargetKind;
use crate::render_task::{RenderTask, StaticRenderTaskSurface, RenderTaskLocation, RenderTaskKind, CachedTask};
use crate::render_task_graph::{RenderTaskGraphBuilder, RenderTaskId};
use crate::frame_builder::add_child_render_task;
use euclid::Scale;

const MAX_CACHE_TASK_SIZE: f32 = 4096.0;

/// Describes a parent dependency for a render task. Render tasks
/// may depend on a surface (e.g. when a surface uses a cached border)
/// or an arbitrary render task (e.g. when a clip mask uses a blurred
/// box-shadow input).
pub enum RenderTaskParent {
    /// Parent is a surface
    Surface(SurfaceIndex),
    /// Parent is a render task
    RenderTask(RenderTaskId),
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum RenderTaskCacheKeyKind {
    BoxShadow(BoxShadowCacheKey),
    Image(ImageCacheKey),
    BorderSegment(BorderSegmentCacheKey),
    LineDecoration(LineDecorationCacheKey),
    FastLinearGradient(FastLinearGradientCacheKey),
    LinearGradient(LinearGradientCacheKey),
    RadialGradient(RadialGradientCacheKey),
    ConicGradient(ConicGradientCacheKey),
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct RenderTaskCacheKey {
    pub size: DeviceIntSize,
    pub kind: RenderTaskCacheKeyKind,
}

#[derive(Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct RenderTaskCacheEntry {
    user_data: Option<[f32; 4]>,
    target_kind: RenderTargetKind,
    is_opaque: bool,
    pub handle: TextureCacheHandle,
    /// If a render task was generated for this cache entry on _this_ frame,
    /// we need to track the task id here. This allows us to hook it up as
    /// a dependency of any parent tasks that make a reqiest from the render
    /// task cache.
    pub render_task_id: Option<RenderTaskId>,
}

#[derive(Debug, MallocSizeOf)]
#[cfg_attr(feature = "capture", derive(Serialize))]
pub enum RenderTaskCacheMarker {}

// A cache of render tasks that are stored in the texture
// cache for usage across frames.
#[derive(Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct RenderTaskCache {
    map: FastHashMap<RenderTaskCacheKey, FreeListHandle<RenderTaskCacheMarker>>,
    cache_entries: FreeList<RenderTaskCacheEntry, RenderTaskCacheMarker>,
}

pub type RenderTaskCacheEntryHandle = WeakFreeListHandle<RenderTaskCacheMarker>;

impl RenderTaskCache {
    pub fn new() -> Self {
        RenderTaskCache {
            map: FastHashMap::default(),
            cache_entries: FreeList::new(),
        }
    }

    pub fn clear(&mut self) {
        self.map.clear();
        self.cache_entries.clear();
    }

    pub fn begin_frame(
        &mut self,
        texture_cache: &mut TextureCache,
    ) {
        profile_scope!("begin_frame");
        // Drop any items from the cache that have been
        // evicted from the texture cache.
        //
        // This isn't actually necessary for the texture
        // cache to be able to evict old render tasks.
        // It will evict render tasks as required, since
        // the access time in the texture cache entry will
        // be stale if this task hasn't been requested
        // for a while.
        //
        // Nonetheless, we should remove stale entries
        // from here so that this hash map doesn't
        // grow indefinitely!
        let cache_entries = &mut self.cache_entries;

        self.map.retain(|_, handle| {
            let retain = texture_cache.is_allocated(
                &cache_entries.get(handle).handle,
            );
            if !retain {
                let handle = mem::replace(handle, FreeListHandle::invalid());
                cache_entries.free(handle);
            }
            retain
        });

        // Clear out the render task ID of any remaining cache entries that were drawn
        // on the previous frame, so we don't accidentally hook up stale dependencies
        // when building the frame graph.
        for (_, handle) in &self.map {
            let entry = self.cache_entries.get_mut(handle);
            entry.render_task_id = None;
        }
    }

    fn alloc_render_task(
        render_task: &mut RenderTask,
        entry: &mut RenderTaskCacheEntry,
        gpu_cache: &mut GpuCache,
        texture_cache: &mut TextureCache,
    ) {
        // Find out what size to alloc in the texture cache.
        let size = render_task.location.size();
        let target_kind = render_task.target_kind();

        // Select the right texture page to allocate from.
        let image_format = match target_kind {
            RenderTargetKind::Color => texture_cache.shared_color_expected_format(),
            RenderTargetKind::Alpha => texture_cache.shared_alpha_expected_format(),
        };

        let flags = if entry.is_opaque {
            ImageDescriptorFlags::IS_OPAQUE
        } else {
            ImageDescriptorFlags::empty()
        };

        let descriptor = ImageDescriptor::new(
            size.width,
            size.height,
            image_format,
            flags,
        );

        // Allocate space in the texture cache, but don't supply
        // and CPU-side data to be uploaded.
        texture_cache.update(
            &mut entry.handle,
            descriptor,
            TextureFilter::Linear,
            None,
            entry.user_data.unwrap_or([0.0; 4]),
            DirtyRect::All,
            gpu_cache,
            None,
            render_task.uv_rect_kind(),
            Eviction::Auto,
            TargetShader::Default,
        );

        // Get the allocation details in the texture cache, and store
        // this in the render task. The renderer will draw this task
        // into the appropriate rect of the texture cache on this frame.
        let (texture_id, uv_rect, _, _, _) =
            texture_cache.get_cache_location(&entry.handle);

        let surface = StaticRenderTaskSurface::TextureCache {
            texture: texture_id,
            target_kind,
        };

        render_task.location = RenderTaskLocation::Static {
            surface,
            rect: uv_rect.to_i32(),
        };
    }

    pub fn request_render_task<F>(
        &mut self,
        key: RenderTaskCacheKey,
        texture_cache: &mut TextureCache,
        gpu_cache: &mut GpuCache,
        rg_builder: &mut RenderTaskGraphBuilder,
        user_data: Option<[f32; 4]>,
        is_opaque: bool,
        parent: RenderTaskParent,
        surfaces: &[SurfaceInfo],
        f: F,
    ) -> Result<RenderTaskId, ()>
    where
        F: FnOnce(&mut RenderTaskGraphBuilder) -> Result<RenderTaskId, ()>,
    {
        let size = key.size;
        // Get the texture cache handle for this cache key,
        // or create one.
        let cache_entries = &mut self.cache_entries;
        let entry_handle = self.map.entry(key).or_insert_with(|| {
            let entry = RenderTaskCacheEntry {
                handle: TextureCacheHandle::invalid(),
                user_data,
                target_kind: RenderTargetKind::Color, // will be set below.
                is_opaque,
                render_task_id: None,
            };
            cache_entries.insert(entry)
        });
        let cache_entry = cache_entries.get_mut(entry_handle);

        // Check if this texture cache handle is valid.
        if texture_cache.request(&cache_entry.handle, gpu_cache) {
            // Invoke user closure to get render task chain
            // to draw this into the texture cache.
            let render_task_id = f(rg_builder)?;

            cache_entry.user_data = user_data;
            cache_entry.is_opaque = is_opaque;
            cache_entry.render_task_id = Some(render_task_id);

            let render_task = rg_builder.get_task_mut(render_task_id);

            render_task.mark_cached(entry_handle.weak());
            cache_entry.target_kind = render_task.kind.target_kind();

            RenderTaskCache::alloc_render_task(
                render_task,
                cache_entry,
                gpu_cache,
                texture_cache,
            );
        }

        // If this render task cache is being drawn this frame, ensure we hook up the
        // render task for it as a dependency of any render task that uses this as
        // an input source.
        if let Some(render_task_id) = cache_entry.render_task_id {
            match parent {
                RenderTaskParent::Surface(surface_index) => {
                    // If parent is a surface, use helper fn to add this dependency,
                    // which correctly takes account of the render task configuration
                    // of the surface.
                    add_child_render_task(
                        surface_index,
                        render_task_id,
                        surfaces,
                        rg_builder
                    );
                }
                RenderTaskParent::RenderTask(parent_render_task_id) => {
                    // For render tasks, just add it as a direct dependency on the
                    // task graph builder.
                    rg_builder.add_dependency(
                        parent_render_task_id,
                        render_task_id,
                    );
                }
            }

            return Ok(render_task_id);
        }

        let target_kind = cache_entry.target_kind;
        let mut task = RenderTask::new(
            RenderTaskLocation::CacheRequest { size, },
            RenderTaskKind::Cached(CachedTask {
                target_kind,
            }),
        );
        task.mark_cached(entry_handle.weak());
        let render_task_id = rg_builder.add().init(task);

        Ok(render_task_id)
    }

    pub fn get_cache_entry(
        &self,
        handle: &RenderTaskCacheEntryHandle,
    ) -> &RenderTaskCacheEntry {
        self.cache_entries
            .get_opt(handle)
            .expect("bug: invalid render task cache handle")
    }

    #[allow(dead_code)]
    pub fn get_cache_item_for_render_task(&self,
                                          texture_cache: &TextureCache,
                                          key: &RenderTaskCacheKey)
                                          -> CacheItem {
        // Get the texture cache handle for this cache key.
        let handle = self.map.get(key).unwrap();
        let cache_entry = self.cache_entries.get(handle);
        texture_cache.get(&cache_entry.handle)
    }

    #[allow(dead_code)]
    pub fn get_allocated_size_for_render_task(&self,
                                              texture_cache: &TextureCache,
                                              key: &RenderTaskCacheKey)
                                              -> Option<usize> {
        let handle = self.map.get(key).unwrap();
        let cache_entry = self.cache_entries.get(handle);
        texture_cache.get_allocated_size(&cache_entry.handle)
    }
}

// TODO(gw): Rounding the content rect here to device pixels is not
// technically correct. Ideally we should ceil() here, and ensure that
// the extra part pixel in the case of fractional sizes is correctly
// handled. For now, just use rounding which passes the existing
// Gecko tests.
// Note: zero-square tasks are prohibited in WR task graph, so
// we ensure each dimension to be at least the length of 1 after rounding.
pub fn to_cache_size(size: LayoutSize, device_pixel_scale: &mut Scale<f32, LayoutPixel, DevicePixel>) -> DeviceIntSize {
    let mut device_size = (size * *device_pixel_scale).round();

    if device_size.width > MAX_CACHE_TASK_SIZE || device_size.height > MAX_CACHE_TASK_SIZE {
        let scale = MAX_CACHE_TASK_SIZE / f32::max(device_size.width, device_size.height);
        *device_pixel_scale = *device_pixel_scale * Scale::new(scale);
        device_size = (size * *device_pixel_scale).round();
    }

    DeviceIntSize::new(
        1.max(device_size.width as i32),
        1.max(device_size.height as i32),
    )
}
<commit_msg>Bug 1705024 - Evict unused cached render tasks after 10 frames. r=gfx-reviewers,gw<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use api::{ImageDescriptor, ImageDescriptorFlags, DirtyRect};
use api::units::*;
use crate::border::BorderSegmentCacheKey;
use crate::box_shadow::{BoxShadowCacheKey};
use crate::device::TextureFilter;
use crate::freelist::{FreeList, FreeListHandle, WeakFreeListHandle};
use crate::gpu_cache::GpuCache;
use crate::internal_types::FastHashMap;
use crate::picture::{SurfaceIndex, SurfaceInfo};
use crate::prim_store::image::ImageCacheKey;
use crate::prim_store::gradient::{
    FastLinearGradientCacheKey, LinearGradientCacheKey, RadialGradientCacheKey,
    ConicGradientCacheKey,
};
use crate::prim_store::line_dec::LineDecorationCacheKey;
use crate::resource_cache::CacheItem;
use std::{mem, usize, f32, i32};
use crate::texture_cache::{TextureCache, TextureCacheHandle, Eviction, TargetShader};
use crate::render_target::RenderTargetKind;
use crate::render_task::{RenderTask, StaticRenderTaskSurface, RenderTaskLocation, RenderTaskKind, CachedTask};
use crate::render_task_graph::{RenderTaskGraphBuilder, RenderTaskId};
use crate::frame_builder::add_child_render_task;
use euclid::Scale;

const MAX_CACHE_TASK_SIZE: f32 = 4096.0;

/// Describes a parent dependency for a render task. Render tasks
/// may depend on a surface (e.g. when a surface uses a cached border)
/// or an arbitrary render task (e.g. when a clip mask uses a blurred
/// box-shadow input).
pub enum RenderTaskParent {
    /// Parent is a surface
    Surface(SurfaceIndex),
    /// Parent is a render task
    RenderTask(RenderTaskId),
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum RenderTaskCacheKeyKind {
    BoxShadow(BoxShadowCacheKey),
    Image(ImageCacheKey),
    BorderSegment(BorderSegmentCacheKey),
    LineDecoration(LineDecorationCacheKey),
    FastLinearGradient(FastLinearGradientCacheKey),
    LinearGradient(LinearGradientCacheKey),
    RadialGradient(RadialGradientCacheKey),
    ConicGradient(ConicGradientCacheKey),
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct RenderTaskCacheKey {
    pub size: DeviceIntSize,
    pub kind: RenderTaskCacheKeyKind,
}

#[derive(Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct RenderTaskCacheEntry {
    user_data: Option<[f32; 4]>,
    target_kind: RenderTargetKind,
    is_opaque: bool,
    frame_id: u64,
    pub handle: TextureCacheHandle,
    /// If a render task was generated for this cache entry on _this_ frame,
    /// we need to track the task id here. This allows us to hook it up as
    /// a dependency of any parent tasks that make a reqiest from the render
    /// task cache.
    pub render_task_id: Option<RenderTaskId>,
}

#[derive(Debug, MallocSizeOf)]
#[cfg_attr(feature = "capture", derive(Serialize))]
pub enum RenderTaskCacheMarker {}

// A cache of render tasks that are stored in the texture
// cache for usage across frames.
#[derive(Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct RenderTaskCache {
    map: FastHashMap<RenderTaskCacheKey, FreeListHandle<RenderTaskCacheMarker>>,
    cache_entries: FreeList<RenderTaskCacheEntry, RenderTaskCacheMarker>,
    frame_id: u64,
}

pub type RenderTaskCacheEntryHandle = WeakFreeListHandle<RenderTaskCacheMarker>;

impl RenderTaskCache {
    pub fn new() -> Self {
        RenderTaskCache {
            map: FastHashMap::default(),
            cache_entries: FreeList::new(),
            frame_id: 0,
        }
    }

    pub fn clear(&mut self) {
        self.map.clear();
        self.cache_entries.clear();
    }

    pub fn begin_frame(
        &mut self,
        texture_cache: &mut TextureCache,
    ) {
        self.frame_id += 1;
        profile_scope!("begin_frame");
        // Drop any items from the cache that have been
        // evicted from the texture cache.
        //
        // This isn't actually necessary for the texture
        // cache to be able to evict old render tasks.
        // It will evict render tasks as required, since
        // the access time in the texture cache entry will
        // be stale if this task hasn't been requested
        // for a while.
        //
        // Nonetheless, we should remove stale entries
        // from here so that this hash map doesn't
        // grow indefinitely!
        let cache_entries = &mut self.cache_entries;
        let frame_id = self.frame_id;

        self.map.retain(|_, handle| {
            let mut retain = texture_cache.is_allocated(
                &cache_entries.get(handle).handle,
            );
            if retain {
                let entry = cache_entries.get_mut(&handle);
                if frame_id > entry.frame_id + 10 {
                    texture_cache.evict_handle(&entry.handle);
                    retain = false;
                }
            }

            if !retain {
                let handle = mem::replace(handle, FreeListHandle::invalid());
                cache_entries.free(handle);
            }

            retain
        });

        // Clear out the render task ID of any remaining cache entries that were drawn
        // on the previous frame, so we don't accidentally hook up stale dependencies
        // when building the frame graph.
        for (_, handle) in &self.map {
            let entry = self.cache_entries.get_mut(handle);
            entry.render_task_id = None;
        }
    }

    fn alloc_render_task(
        render_task: &mut RenderTask,
        entry: &mut RenderTaskCacheEntry,
        gpu_cache: &mut GpuCache,
        texture_cache: &mut TextureCache,
    ) {
        // Find out what size to alloc in the texture cache.
        let size = render_task.location.size();
        let target_kind = render_task.target_kind();

        // Select the right texture page to allocate from.
        let image_format = match target_kind {
            RenderTargetKind::Color => texture_cache.shared_color_expected_format(),
            RenderTargetKind::Alpha => texture_cache.shared_alpha_expected_format(),
        };

        let flags = if entry.is_opaque {
            ImageDescriptorFlags::IS_OPAQUE
        } else {
            ImageDescriptorFlags::empty()
        };

        let descriptor = ImageDescriptor::new(
            size.width,
            size.height,
            image_format,
            flags,
        );

        // Allocate space in the texture cache, but don't supply
        // and CPU-side data to be uploaded.
        texture_cache.update(
            &mut entry.handle,
            descriptor,
            TextureFilter::Linear,
            None,
            entry.user_data.unwrap_or([0.0; 4]),
            DirtyRect::All,
            gpu_cache,
            None,
            render_task.uv_rect_kind(),
            Eviction::Auto,
            TargetShader::Default,
        );

        // Get the allocation details in the texture cache, and store
        // this in the render task. The renderer will draw this task
        // into the appropriate rect of the texture cache on this frame.
        let (texture_id, uv_rect, _, _, _) =
            texture_cache.get_cache_location(&entry.handle);

        let surface = StaticRenderTaskSurface::TextureCache {
            texture: texture_id,
            target_kind,
        };

        render_task.location = RenderTaskLocation::Static {
            surface,
            rect: uv_rect.to_i32(),
        };
    }

    pub fn request_render_task<F>(
        &mut self,
        key: RenderTaskCacheKey,
        texture_cache: &mut TextureCache,
        gpu_cache: &mut GpuCache,
        rg_builder: &mut RenderTaskGraphBuilder,
        user_data: Option<[f32; 4]>,
        is_opaque: bool,
        parent: RenderTaskParent,
        surfaces: &[SurfaceInfo],
        f: F,
    ) -> Result<RenderTaskId, ()>
    where
        F: FnOnce(&mut RenderTaskGraphBuilder) -> Result<RenderTaskId, ()>,
    {
        let frame_id = self.frame_id;
        let size = key.size;
        // Get the texture cache handle for this cache key,
        // or create one.
        let cache_entries = &mut self.cache_entries;
        let entry_handle = self.map.entry(key).or_insert_with(|| {
            let entry = RenderTaskCacheEntry {
                handle: TextureCacheHandle::invalid(),
                user_data,
                target_kind: RenderTargetKind::Color, // will be set below.
                is_opaque,
                frame_id,
                render_task_id: None,
            };
            cache_entries.insert(entry)
        });
        let cache_entry = cache_entries.get_mut(entry_handle);
        cache_entry.frame_id = self.frame_id;

        // Check if this texture cache handle is valid.
        if texture_cache.request(&cache_entry.handle, gpu_cache) {
            // Invoke user closure to get render task chain
            // to draw this into the texture cache.
            let render_task_id = f(rg_builder)?;

            cache_entry.user_data = user_data;
            cache_entry.is_opaque = is_opaque;
            cache_entry.render_task_id = Some(render_task_id);

            let render_task = rg_builder.get_task_mut(render_task_id);

            render_task.mark_cached(entry_handle.weak());
            cache_entry.target_kind = render_task.kind.target_kind();

            RenderTaskCache::alloc_render_task(
                render_task,
                cache_entry,
                gpu_cache,
                texture_cache,
            );
        }

        // If this render task cache is being drawn this frame, ensure we hook up the
        // render task for it as a dependency of any render task that uses this as
        // an input source.
        if let Some(render_task_id) = cache_entry.render_task_id {
            match parent {
                RenderTaskParent::Surface(surface_index) => {
                    // If parent is a surface, use helper fn to add this dependency,
                    // which correctly takes account of the render task configuration
                    // of the surface.
                    add_child_render_task(
                        surface_index,
                        render_task_id,
                        surfaces,
                        rg_builder
                    );
                }
                RenderTaskParent::RenderTask(parent_render_task_id) => {
                    // For render tasks, just add it as a direct dependency on the
                    // task graph builder.
                    rg_builder.add_dependency(
                        parent_render_task_id,
                        render_task_id,
                    );
                }
            }

            return Ok(render_task_id);
        }

        let target_kind = cache_entry.target_kind;
        let mut task = RenderTask::new(
            RenderTaskLocation::CacheRequest { size, },
            RenderTaskKind::Cached(CachedTask {
                target_kind,
            }),
        );
        task.mark_cached(entry_handle.weak());
        let render_task_id = rg_builder.add().init(task);

        Ok(render_task_id)
    }

    pub fn get_cache_entry(
        &self,
        handle: &RenderTaskCacheEntryHandle,
    ) -> &RenderTaskCacheEntry {
        self.cache_entries
            .get_opt(handle)
            .expect("bug: invalid render task cache handle")
    }

    #[allow(dead_code)]
    pub fn get_cache_item_for_render_task(&self,
                                          texture_cache: &TextureCache,
                                          key: &RenderTaskCacheKey)
                                          -> CacheItem {
        // Get the texture cache handle for this cache key.
        let handle = self.map.get(key).unwrap();
        let cache_entry = self.cache_entries.get(handle);
        texture_cache.get(&cache_entry.handle)
    }

    #[allow(dead_code)]
    pub fn get_allocated_size_for_render_task(&self,
                                              texture_cache: &TextureCache,
                                              key: &RenderTaskCacheKey)
                                              -> Option<usize> {
        let handle = self.map.get(key).unwrap();
        let cache_entry = self.cache_entries.get(handle);
        texture_cache.get_allocated_size(&cache_entry.handle)
    }
}

// TODO(gw): Rounding the content rect here to device pixels is not
// technically correct. Ideally we should ceil() here, and ensure that
// the extra part pixel in the case of fractional sizes is correctly
// handled. For now, just use rounding which passes the existing
// Gecko tests.
// Note: zero-square tasks are prohibited in WR task graph, so
// we ensure each dimension to be at least the length of 1 after rounding.
pub fn to_cache_size(size: LayoutSize, device_pixel_scale: &mut Scale<f32, LayoutPixel, DevicePixel>) -> DeviceIntSize {
    let mut device_size = (size * *device_pixel_scale).round();

    if device_size.width > MAX_CACHE_TASK_SIZE || device_size.height > MAX_CACHE_TASK_SIZE {
        let scale = MAX_CACHE_TASK_SIZE / f32::max(device_size.width, device_size.height);
        *device_pixel_scale = *device_pixel_scale * Scale::new(scale);
        device_size = (size * *device_pixel_scale).round();
    }

    DeviceIntSize::new(
        1.max(device_size.width as i32),
        1.max(device_size.height as i32),
    )
}
<|endoftext|>


<commit_before>use crate::{render_object::*, utils::Point};

/// The target of the popup, given as an entity or as fixed point coordinate.
#[derive(Clone, Debug, PartialEq)]
pub enum PopupTarget {
    /// the entity of the target (Entity).
    Entity(Entity),

    /// the point coordinate (f64, f64).
    Point(Point),
}

impl Default for PopupTarget {
    fn default() -> Self {
	Self::Point(Point::new(0.0, 0.0))
    }
}

impl From<Entity> for PopupTarget {
    fn from(entity: Entity) -> Self {
	Self::Entity(entity)
    }
}

impl From<Point> for PopupTarget {
    fn from(point: Point) -> Self {
	Self::Point(point)
    }
}

impl IntoPropertySource<PopupTarget> for Entity {
    fn into_source(self) -> PropertySource<PopupTarget> {
	PropertySource::Value(self.into())
    }
}

impl IntoPropertySource<PopupTarget> for Point {
    fn into_source(self) -> PropertySource<PopupTarget> {
	PropertySource::Value(self.into())
    }
}

/// Defines popup placement options relative to its target.
#[derive(Clone, Debug, PartialEq)]
pub enum Placement {
    Bottom,
    BottomLeft,
    BottomRight,
    Left,
    Right,
    Top,
    TopLeft,
    TopRight,
}

impl Default for Placement {
    fn default() -> Self {
	Self::Bottom
    }
}
impl Placement {
    /// Returns the placement name.
    pub fn get_name(&self, index: i32) -> String {
	match index {
	    0 => "Bottom".to_string(),
	    1 => "BottomLeft".to_string(),
	    2 => "BottomRight".to_string(),
	    3 => "Left".to_string(),
	    4 => "Right".to_string(),
	    5 => "Top".to_string(),
	    6 => "TopLeft".to_string(),
	    7 => "TopRight".to_string(),
	    _ => {
		eprintln!("popup: placement variant with index {} not coverd!", index);
		std::process::exit(1);
	    }
	}
    }

    /// Returns the placement index.
    pub fn get_index(&self, string: &str) -> u32 {
	match string {
	    "Bottom" => 0,
	    "BottomLeft" => 1,
	    "BottomRight" => 2,
	    "Left" => 3,
	    "Right" => 4,
	    "Top" => 5,
	    "TopLeft" => 6,
	    "TopRight" => 7,
	    _ => {
		eprintln!("popup: placement variant {} not coverd!", string);
		std::process::exit(1);
	    }
	}
    }

    /// Place the popup widget relative to the `bottom` of its parent target.
    pub fn bottom(self) -> Self {
	Self::Bottom
    }

    /// Place the popup widget relative to the `bottom` and `left` edge of its parent target.
    pub fn bottom_left(self) -> Self {
	Self::BottomLeft
    }

    /// Place the popup widget relative to the `bottom` and `right` edge of its parent target.
    pub fn bottom_right(self) -> Self {
	Self::BottomRight
    }

    /// Place the popup widget relative to the left of its parent target.
    pub fn left(self) -> Self {
	Self::Left
    }

    /// Place the popup widget relative to the `right` of its parent target.
    pub fn right(self) -> Self {
	Self::Right
    }
    /// Place the popup widget relative to the `top` of its parent target.
    pub fn top(self) -> Self {
	Self::Top
    }

    /// Place the popup widget relative to the `top` of its parent target.
    /// Place the popup widget relative to the `top` and `left` edge of its parent target.
    pub fn top_left(self) -> Self {
	Self::TopLeft
    }

    /// Place the popup widget relative to the `top` and `right` edge of its parent target.
    pub fn top_right(self) -> Self {
	Self::TopRight
    }
}

into_property_source!(Placement);

/// The `PopupRenderObject` is used to render the contents of a `Popup` widget inside a recangle.
pub struct PopupRenderObject(RectangleRenderObject);

impl PopupRenderObject {
    pub fn new() -> Self {
	Self::default()
    }
}
impl Default for PopupRenderObject {
    fn default() -> Self {
	Self(RectangleRenderObject)
    }
}

impl Into<Box<dyn RenderObject>> for PopupRenderObject {
    fn into(self) -> Box<dyn RenderObject> {
	Box::new(self)
    }
}

impl RenderObject for PopupRenderObject {
    fn render_self(&self, ctx: &mut Context, global_position: &Point) {
	if let Some(target) = ctx.widget().try_clone::<PopupTarget>("target") {
	    let current_bounds: Rectangle = ctx.widget().clone("bounds");
	    let current_constraint: Constraint = ctx.widget().clone("constraint");

	    let target_bounds = match target {
		PopupTarget::Entity(entity) => {
		    let target_position: Point = ctx.get_widget(entity).clone("position");

		    // WARNING: target_bounds are only reflecting the
		    // actual effective size, if refered in
		    // post_layout_update function. Otherwise the
		    // bounds will refere to the space bounds
		    // available to the given widget.
		    let mut target_bounds: Rectangle = ctx.get_widget(entity).clone("bounds");
		    target_bounds.set_position(target_position);
		    target_bounds
		}
		PopupTarget::Point(mut point) => {
		    point.set_x(point.x() + current_bounds.width() / 2.0);
		    point.set_y(point.y() + current_bounds.height() / 2.0);
		    Rectangle::new(point, (0.0, 0.0))
		}
	    };

	    let placement: Placement = ctx.widget().clone_or_default("placement");
	    let offset: f64 = ctx.widget().clone_or_default("offset");

	    let new_popup_bounds = match placement {
		Placement::Left => {
		    let current_v_align: Alignment = ctx.widget().clone("v_align");

		    let x = target_bounds.x() - current_bounds.width() - offset;
		    let y = current_v_align.align_position(
			target_bounds.height(),
			current_bounds.height(),
			target_bounds.y(),
			target_bounds.y() + target_bounds.height(),
		    );

		    let width = current_bounds.width();
		    let height = current_v_align.align_measure(
			target_bounds.height(),
			current_bounds.height(),
			0.0,
			0.0,
		    );

		    Rectangle::new((x, y), current_constraint.perform((width, height)))
		}
		Placement::Right => {
		    let current_v_align: Alignment = ctx.widget().clone("v_align");

		    let x = target_bounds.x() + target_bounds.width() + offset;
		    let y = current_v_align.align_position(
			target_bounds.height(),
			current_bounds.height(),
			target_bounds.y(),
			target_bounds.y() + target_bounds.height(),
		    );

		    let width = current_bounds.width();
		    let height = current_v_align.align_measure(
			target_bounds.height(),
			current_bounds.height(),
			0.0,
			0.0,
		    );

		    Rectangle::new((x, y), current_constraint.perform((width, height)))
		}
		Placement::Top => {
		    let current_h_align: Alignment = ctx.widget().clone("h_align");

		    let x = current_h_align.align_position(
			target_bounds.width(),
			current_bounds.width(),
			target_bounds.x(),
			target_bounds.x() + target_bounds.width(),
		    );
		    let y = target_bounds.y() - current_bounds.height() - offset;
		    let width = current_h_align.align_measure(
			target_bounds.width(),
			current_bounds.width(),
			0.0,
			0.0,
		    );
		    let height = current_bounds.height();

		    Rectangle::new((x, y), current_constraint.perform((width, height)))
		}
		Placement::TopLeft => {
		    let current_h_align: Alignment = ctx.widget().clone("h_align");

		    let x = current_h_align.align_position(
			target_bounds.width(),
			current_bounds.width(),
			target_bounds.x(),
			target_bounds.x() + target_bounds.width(),
		    );
		    let y = target_bounds.y() - current_bounds.height() - offset;
		    let width = current_h_align.align_measure(
			target_bounds.width(),
			current_bounds.width(),
			0.0,
			0.0,
		    );
		    let height = current_bounds.height();

		    Rectangle::new((x, y), current_constraint.perform((width, height)))
		}
		Placement::TopRight => {
		    let current_h_align: Alignment = ctx.widget().clone("h_align");

		    let x = current_h_align.align_position(
			target_bounds.width(),
			current_bounds.width(),
			target_bounds.x(),
			target_bounds.x() + target_bounds.width(),
		    );
		    let y = target_bounds.y() - current_bounds.height() - offset;
		    let width = current_h_align.align_measure(
			target_bounds.width(),
			current_bounds.width(),
			0.0,
			0.0,
		    );
		    let height = current_bounds.height();

		    Rectangle::new((x, y), current_constraint.perform((width, height)))
		}
		Placement::Bottom => {
		    let current_h_align: Alignment = ctx.widget().clone("h_align");

		    let x = current_h_align.align_position(
			target_bounds.width(),
			current_bounds.width(),
			target_bounds.x(),
			target_bounds.x() + target_bounds.width(),
		    );
		    let y = target_bounds.y() + target_bounds.height() + offset;
		    let width = current_h_align.align_measure(
			target_bounds.width(),
			current_bounds.width(),
			0.0,
			0.0,
		    );
		    let height = current_bounds.height();

		    Rectangle::new((x, y), current_constraint.perform((width, height)))
		}
		Placement::BottomLeft => {
		    let current_h_align: Alignment = ctx.widget().clone("h_align");

		    let x = current_h_align.align_position(
			target_bounds.width(),
			current_bounds.width(),
			target_bounds.x(),
			target_bounds.x() + target_bounds.width(),
		    );
		    let y = target_bounds.y() + target_bounds.height() + offset;
		    let width = current_h_align.align_measure(
			target_bounds.width(),
			current_bounds.width(),
			0.0,
			0.0,
		    );
		    let height = current_bounds.height();

		    Rectangle::new((x, y), current_constraint.perform((width, height)))
		}
		Placement::BottomRight => {
		    let current_h_align: Alignment = ctx.widget().clone("h_align");

		    let x = current_h_align.align_position(
			target_bounds.width(),
			current_bounds.width(),
			target_bounds.x(),
			target_bounds.x() + target_bounds.width(),
		    );
		    let y = target_bounds.y() + target_bounds.height() + offset;
		    let width = current_h_align.align_measure(
			target_bounds.width(),
			current_bounds.width(),
			0.0,
			0.0,
		    );
		    let height = current_bounds.height();

		    Rectangle::new((x, y), current_constraint.perform((width, height)))
		}
	    };

	    ctx.widget().set::<Rectangle>("bounds", new_popup_bounds);
	} else {
	    println!("Target not found");
	}

	self.0.render_self(ctx, global_position);
    }
}
<commit_msg>orbtk_core: render_object popup update<commit_after>use crate::{render_object::*, utils::Point};

/// The target of the popup, given as an entity or as fixed point coordinate.
#[derive(Clone, Debug, PartialEq)]
pub enum PopupTarget {
    /// the entity of the target (Entity).
    Entity(Entity),

    /// the point coordinate (f64, f64).
    Point(Point),
}

impl Default for PopupTarget {
    fn default() -> Self {
	Self::Point(Point::new(0.0, 0.0))
    }
}

impl From<Entity> for PopupTarget {
    fn from(entity: Entity) -> Self {
	Self::Entity(entity)
    }
}

impl From<Point> for PopupTarget {
    fn from(point: Point) -> Self {
	Self::Point(point)
    }
}

impl IntoPropertySource<PopupTarget> for Entity {
    fn into_source(self) -> PropertySource<PopupTarget> {
	PropertySource::Value(self.into())
    }
}

impl IntoPropertySource<PopupTarget> for Point {
    fn into_source(self) -> PropertySource<PopupTarget> {
	PropertySource::Value(self.into())
    }
}

/// Defines popup placement options relative to its target.
#[derive(Clone, Debug, PartialEq)]
pub enum Placement {
    Bottom,
    Left,
    Right,
    Top,
}

impl Default for Placement {
    fn default() -> Self {
	Self::Bottom
    }
}
impl Placement {
    /// Returns the placement name.
    pub fn get_name(&self, index: i32) -> String {
	match index {
	    0 => "Bottom".to_string(),
	    1 => "Left".to_string(),
	    2 => "Right".to_string(),
	    3 => "Top".to_string(),
	    _ => {
		eprintln!("popup: placement variant with index {} not coverd!", index);
		std::process::exit(1);
	    }
	}
    }

    /// Returns the placement index.
    pub fn get_index(&self, string: &str) -> u32 {
	match string {
	    "Bottom" => 0,
	    "Left" => 1,
	    "Right" => 2,
	    "Top" => 3,
	    _ => {
		eprintln!("popup: placement variant {} not coverd!", string);
		std::process::exit(1);
	    }
	}
    }

    /// Place the popup widget relative to the `bottom` of its parent target.
    pub fn bottom(self) -> Self {
	Self::Bottom
    }

    /// Place the popup widget relative to the left of its parent target.
    pub fn left(self) -> Self {
	Self::Left
    }

    /// Place the popup widget relative to the `right` of its parent target.
    pub fn right(self) -> Self {
	Self::Right
    }
    /// Place the popup widget relative to the `top` of its parent target.
    pub fn top(self) -> Self {
	Self::Top
    }
}

into_property_source!(Placement);

/// The `PopupRenderObject` is used to render the contents of a `Popup` widget inside a recangle.
pub struct PopupRenderObject(RectangleRenderObject);

impl PopupRenderObject {
    pub fn new() -> Self {
	Self::default()
    }
}
impl Default for PopupRenderObject {
    fn default() -> Self {
	Self(RectangleRenderObject)
    }
}

impl Into<Box<dyn RenderObject>> for PopupRenderObject {
    fn into(self) -> Box<dyn RenderObject> {
	Box::new(self)
    }
}

impl RenderObject for PopupRenderObject {
    fn render_self(&self, ctx: &mut Context, global_position: &Point) {
	if let Some(target) = ctx.widget().try_clone::<PopupTarget>("target") {
	    let current_bounds: Rectangle = ctx.widget().clone("bounds");
	    let current_constraint: Constraint = ctx.widget().clone("constraint");

	    let target_bounds = match target {
		PopupTarget::Entity(entity) => {
		    let target_position: Point = ctx.get_widget(entity).clone("position");

		    // WARNING: target_bounds are only reflecting the
		    // actual effective size, if refered in
		    // post_layout_update function. Otherwise the
		    // bounds will refere to the space bounds
		    // available to the given widget.
		    let mut target_bounds: Rectangle = ctx.get_widget(entity).clone("bounds");
		    target_bounds.set_position(target_position);
		    target_bounds
		}
		PopupTarget::Point(mut point) => {
		    point.set_x(point.x() + current_bounds.width() / 2.0);
		    point.set_y(point.y() + current_bounds.height() / 2.0);
		    Rectangle::new(point, (0.0, 0.0))
		}
	    };

	    let placement: Placement = ctx.widget().clone_or_default("placement");
	    let offset: f64 = ctx.widget().clone_or_default("offset");

	    let new_popup_bounds = match placement {
		Placement::Bottom => {
		    let current_h_align: Alignment = ctx.widget().clone("h_align");

		    let x = current_h_align.align_position(
			target_bounds.width(),
			current_bounds.width(),
			target_bounds.x(),
			target_bounds.x() + target_bounds.width(),
		    );
		    let y = target_bounds.y() + target_bounds.height() + offset;
		    let width = current_h_align.align_measure(
			target_bounds.width(),
			current_bounds.width(),
			0.0,
			0.0,
		    );
		    let height = current_bounds.height();

		    Rectangle::new((x, y), current_constraint.perform((width, height)))
		}
		Placement::Left => {
		    let current_v_align: Alignment = ctx.widget().clone("v_align");

		    let x = target_bounds.x() - current_bounds.width() - offset;
		    let y = current_v_align.align_position(
			target_bounds.height(),
			current_bounds.height(),
			target_bounds.y(),
			target_bounds.y() + target_bounds.height(),
		    );

		    let width = current_bounds.width();
		    let height = current_v_align.align_measure(
			target_bounds.height(),
			current_bounds.height(),
			0.0,
			0.0,
		    );

		    Rectangle::new((x, y), current_constraint.perform((width, height)))
		}
		Placement::Right => {
		    let current_v_align: Alignment = ctx.widget().clone("v_align");

		    let x = target_bounds.x() + target_bounds.width() + offset;
		    let y = current_v_align.align_position(
			target_bounds.height(),
			current_bounds.height(),
			target_bounds.y(),
			target_bounds.y() + target_bounds.height(),
		    );

		    let width = current_bounds.width();
		    let height = current_v_align.align_measure(
			target_bounds.height(),
			current_bounds.height(),
			0.0,
			0.0,
		    );

		    Rectangle::new((x, y), current_constraint.perform((width, height)))
		}
		Placement::Top => {
		    let current_h_align: Alignment = ctx.widget().clone("h_align");

		    let x = current_h_align.align_position(
			target_bounds.width(),
			current_bounds.width(),
			target_bounds.x(),
			target_bounds.x() + target_bounds.width(),
		    );
		    let y = target_bounds.y() - current_bounds.height() - offset;
		    let width = current_h_align.align_measure(
			target_bounds.width(),
			current_bounds.width(),
			0.0,
			0.0,
		    );
		    let height = current_bounds.height();

		    Rectangle::new((x, y), current_constraint.perform((width, height)))
		}
	    };

	    ctx.widget().set::<Rectangle>("bounds", new_popup_bounds);
	} else {
	    println!("Target not found");
	}

	self.0.render_self(ctx, global_position);
    }
}
<|endoftext|>


<commit_before>pub fn nth(n: usize) -> Result<usize, String> {
    if n == 0 {
        Err("For some reason we're 1-indexing…".to_string())
    } else {
        let mut ps = vec![2];
        let mut q = 3;
        while ps.len() < n {
            if ps.iter().all(|p| q % p != 0) {
                ps.push(q);
            }
            q += 2;
        }
        ps.last().map(|&p| p).ok_or("OH NO".to_string())
    }
}
<commit_msg>Even better rust<commit_after>pub fn nth(n: usize) -> Result<usize, String> {
    if n == 0 {
        Err("For some reason we're 1-indexing…".to_string())
    } else {
        let mut ps = vec![2];
        let mut q = 3;
        while ps.len() < n {
            if ps.iter().all(|p| q % p != 0) {
                ps.push(q);
            }
            q += 2;
        }
        ps.pop().ok_or("OH NO".to_string())
    }
}
<|endoftext|>


<commit_before>use opengles;   // FIXME: Should only be for tests.
import glut::{check_loop, create_window, destroy_window, init, init_display_mode, swap_buffers};
import opengles::gl2::{ARRAY_BUFFER, COLOR_BUFFER_BIT, COMPILE_STATUS};
import opengles::gl2::{FRAGMENT_SHADER, LINK_STATUS, NO_ERROR, STATIC_DRAW};
import opengles::gl2::{TRIANGLE_STRIP, VERTEX_SHADER, GLclampf, GLenum};
import opengles::gl2::{GLsizei, GLuint, attach_shader, bind_buffer};
import opengles::gl2::{buffer_data, create_program, clear, clear_color};
import opengles::gl2::{compile_shader, create_shader, draw_arrays};
import opengles::gl2::{enable_vertex_attrib_array, gen_buffers};
import opengles::gl2::{get_attrib_location, get_error, get_program_iv};
import opengles::gl2::{get_shader_info_log, get_shader_iv};
import opengles::gl2::{get_uniform_location, link_program, shader_source};
import opengles::gl2::{use_program, vertex_attrib_pointer_f32};

import comm::{chan, peek, port, recv, send};
import io::println;
import ptr::{addr_of, null};
import str::bytes;
import task::{task_builder, get_opts, run_listener, set_opts};
import vec::unsafe::to_ptr;

fn fragment_shader_source() -> ~str {
    ~"
    #ifdef GLES2
        precision mediump float;
    #endif

        void main(void) {
            gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
        }
    "
}

fn vertex_shader_source() -> ~str {
    ~"
        attribute vec3 aVertexPosition;

        /*uniform mat4 uMVMatrix;
        uniform mat4 uPMatrix;*/

        void main(void) {
            gl_Position = /*uPMatrix * uMVMatrix **/
                vec4(aVertexPosition, 1.0);
        }
    "
}

fn load_shader(source_str: ~str, shader_type: GLenum) -> GLuint {
    let shader_id = create_shader(shader_type);
    shader_source(shader_id, ~[bytes(source_str)]);
    compile_shader(shader_id);

    if get_error() != NO_ERROR {
        println(#fmt("error: %d", get_error() as int));
        fail ~"failed to compile shader with error";
    }

    if get_shader_iv(shader_id, COMPILE_STATUS) == (0 as GLint) {
        println(get_shader_info_log(shader_id));
        fail ~"failed to compile shader";
    }
    ret shader_id;
}

class shader_program {
    let program: GLuint;
    let aVertexPosition: c_int;
    /*let uPMatrix: c_int;
    let uMVMatrix: c_int;*/

    new(program: GLuint) {
        self.program = program;
        self.aVertexPosition = get_attrib_location(program, ~"aVertexPosition");
        /*self.uPMatrix = get_uniform_location(program, "uPMatrix");
        self.uMVMatrix = get_uniform_location(program, "uMVMatrix");*/

        enable_vertex_attrib_array(self.aVertexPosition as GLuint);
    }
}

fn init_shaders() -> shader_program {
    let vertex_shader = load_shader(vertex_shader_source(), VERTEX_SHADER);
    let fragment_shader = load_shader(fragment_shader_source(),
                                      FRAGMENT_SHADER);

    let program = create_program();
    attach_shader(program, vertex_shader);
    attach_shader(program, fragment_shader);
    link_program(program);

    if get_program_iv(program, LINK_STATUS) == (0 as GLint) {
        fail ~"failed to initialize program";
    }

    use_program(program);

    ret shader_program(program);
}

fn init_buffers() -> GLuint {
    let triangle_vertex_buffer = gen_buffers(1 as GLsizei)[0];
    bind_buffer(ARRAY_BUFFER, triangle_vertex_buffer);
    let vertices = ~[
        0.0f32, 1.0f32, 0.0f32,
        1.0f32, 0.0f32, 0.0f32,
        0.0f32, 0.0f32, 0.0f32
    ];
    buffer_data(ARRAY_BUFFER, vertices, STATIC_DRAW);
    ret triangle_vertex_buffer;
}

fn draw_scene(shader_program: shader_program, vertex_buffer: GLuint) {
    clear_color(0.0f32, 0.0f32, 1.0f32, 1.0f32);
    clear(COLOR_BUFFER_BIT);

    bind_buffer(ARRAY_BUFFER, vertex_buffer);
    vertex_attrib_pointer_f32(shader_program.aVertexPosition as GLuint,
                              3 as GLint, false, 0 as GLsizei, 0 as GLuint);
    draw_arrays(TRIANGLE_STRIP, 0 as GLint, 3 as GLint);
}

fn display_callback() {
    let program = init_shaders();
    let vertex_buffer = init_buffers();
    draw_scene(program, vertex_buffer);

    swap_buffers();
}

#[test]
fn test_triangle_and_square() unsafe {
    let builder = task::task().sched_mode(task::osmain);

    let po: port<()> = port();
    let ch = chan(po);
    let _result_ch: chan<()> = builder.spawn_listener(|_port| {
        init();
        init_display_mode(0 as c_uint);
        let window = create_window(~"Rust GLUT");
        display_func(display_callback);

        let wakeup = port();
        let wakeup_chan = chan(wakeup);
        timer_func(1000, || send(wakeup_chan, ()));

        loop {
            check_loop();

            if peek(wakeup) {
                recv(wakeup);
                send(ch, ());
                destroy_window(window);
                break;
            }
        }
    });

    recv(po);
}

<commit_msg>Fix task imports in rust-glut test.rs<commit_after>use opengles;   // FIXME: Should only be for tests.
import glut::{check_loop, create_window, destroy_window, init, init_display_mode, swap_buffers};
import opengles::gl2::{ARRAY_BUFFER, COLOR_BUFFER_BIT, COMPILE_STATUS};
import opengles::gl2::{FRAGMENT_SHADER, LINK_STATUS, NO_ERROR, STATIC_DRAW};
import opengles::gl2::{TRIANGLE_STRIP, VERTEX_SHADER, GLclampf, GLenum};
import opengles::gl2::{GLsizei, GLuint, attach_shader, bind_buffer};
import opengles::gl2::{buffer_data, create_program, clear, clear_color};
import opengles::gl2::{compile_shader, create_shader, draw_arrays};
import opengles::gl2::{enable_vertex_attrib_array, gen_buffers};
import opengles::gl2::{get_attrib_location, get_error, get_program_iv};
import opengles::gl2::{get_shader_info_log, get_shader_iv};
import opengles::gl2::{get_uniform_location, link_program, shader_source};
import opengles::gl2::{use_program, vertex_attrib_pointer_f32};

import comm::{chan, peek, port, recv, send};
import io::println;
import ptr::{addr_of, null};
import str::bytes;
import task::task_builder;
import vec::unsafe::to_ptr;

fn fragment_shader_source() -> ~str {
    ~"
    #ifdef GLES2
        precision mediump float;
    #endif

        void main(void) {
            gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
        }
    "
}

fn vertex_shader_source() -> ~str {
    ~"
        attribute vec3 aVertexPosition;

        /*uniform mat4 uMVMatrix;
        uniform mat4 uPMatrix;*/

        void main(void) {
            gl_Position = /*uPMatrix * uMVMatrix **/
                vec4(aVertexPosition, 1.0);
        }
    "
}

fn load_shader(source_str: ~str, shader_type: GLenum) -> GLuint {
    let shader_id = create_shader(shader_type);
    shader_source(shader_id, ~[bytes(source_str)]);
    compile_shader(shader_id);

    if get_error() != NO_ERROR {
        println(#fmt("error: %d", get_error() as int));
        fail ~"failed to compile shader with error";
    }

    if get_shader_iv(shader_id, COMPILE_STATUS) == (0 as GLint) {
        println(get_shader_info_log(shader_id));
        fail ~"failed to compile shader";
    }
    ret shader_id;
}

class shader_program {
    let program: GLuint;
    let aVertexPosition: c_int;
    /*let uPMatrix: c_int;
    let uMVMatrix: c_int;*/

    new(program: GLuint) {
        self.program = program;
        self.aVertexPosition = get_attrib_location(program, ~"aVertexPosition");
        /*self.uPMatrix = get_uniform_location(program, "uPMatrix");
        self.uMVMatrix = get_uniform_location(program, "uMVMatrix");*/

        enable_vertex_attrib_array(self.aVertexPosition as GLuint);
    }
}

fn init_shaders() -> shader_program {
    let vertex_shader = load_shader(vertex_shader_source(), VERTEX_SHADER);
    let fragment_shader = load_shader(fragment_shader_source(),
                                      FRAGMENT_SHADER);

    let program = create_program();
    attach_shader(program, vertex_shader);
    attach_shader(program, fragment_shader);
    link_program(program);

    if get_program_iv(program, LINK_STATUS) == (0 as GLint) {
        fail ~"failed to initialize program";
    }

    use_program(program);

    ret shader_program(program);
}

fn init_buffers() -> GLuint {
    let triangle_vertex_buffer = gen_buffers(1 as GLsizei)[0];
    bind_buffer(ARRAY_BUFFER, triangle_vertex_buffer);
    let vertices = ~[
        0.0f32, 1.0f32, 0.0f32,
        1.0f32, 0.0f32, 0.0f32,
        0.0f32, 0.0f32, 0.0f32
    ];
    buffer_data(ARRAY_BUFFER, vertices, STATIC_DRAW);
    ret triangle_vertex_buffer;
}

fn draw_scene(shader_program: shader_program, vertex_buffer: GLuint) {
    clear_color(0.0f32, 0.0f32, 1.0f32, 1.0f32);
    clear(COLOR_BUFFER_BIT);

    bind_buffer(ARRAY_BUFFER, vertex_buffer);
    vertex_attrib_pointer_f32(shader_program.aVertexPosition as GLuint,
                              3 as GLint, false, 0 as GLsizei, 0 as GLuint);
    draw_arrays(TRIANGLE_STRIP, 0 as GLint, 3 as GLint);
}

fn display_callback() {
    let program = init_shaders();
    let vertex_buffer = init_buffers();
    draw_scene(program, vertex_buffer);

    swap_buffers();
}

#[test]
fn test_triangle_and_square() unsafe {
    let builder = task::task().sched_mode(task::osmain);

    let po: port<()> = port();
    let ch = chan(po);
    let _result_ch: chan<()> = builder.spawn_listener(|_port| {
        init();
        init_display_mode(0 as c_uint);
        let window = create_window(~"Rust GLUT");
        display_func(display_callback);

        let wakeup = port();
        let wakeup_chan = chan(wakeup);
        timer_func(1000, || send(wakeup_chan, ()));

        loop {
            check_loop();

            if peek(wakeup) {
                recv(wakeup);
                send(ch, ());
                destroy_window(window);
                break;
            }
        }
    });

    recv(po);
}

<|endoftext|>


<commit_before>
#[doc = "a uuid value"]
type uuid = {
    a: u32,
    b: u32,
    c: u32,
    d: u32,
};

#[nolink]
native mod libuuid {
    fn uuid_generate(out: uuid);
    fn uuid_generate_random(out: uuid);
    fn uuid_generate_time(out: uuid);

    fn uuid_parse(s: *u8, uuid: uuid) -> libc::c_int;

    fn uuid_unparse(uuid: uuid, out: *u8);
    fn uuid_unparse_lower(uuid: uuid, out: *u8);
    fn uuid_unparse_upper(uuid: uuid, out: *u8);
}

#[doc = "Create a new uuid"]
fn mk_uuid() -> uuid {
    let uuid = { a: 0u32, b: 0u32, c: 0u32, d: 0u32 };
    libuuid::uuid_generate(uuid);
    uuid
}

#[doc = "Create a uuid from the current time and mac address"]
fn mk_uuid_random() -> uuid {
    let uuid = { a: 0u32, b: 0u32, c: 0u32, d: 0u32 };
    libuuid::uuid_generate_random(uuid);
    uuid
}

#[doc = "Create a uuid from a random number generator"]
fn mk_uuid_time() -> uuid {
    let uuid = { a: 0u32, b: 0u32, c: 0u32, d: 0u32 };
    libuuid::uuid_generate_time(uuid);
    uuid
}

#[doc = "Convert a uuid to a string"]
fn to_str(uuid: uuid) -> str {
    let mut s = "";
    str::reserve(s, 36u);
    unsafe { str::unsafe::set_len(s, 36u); }
    str::as_buf(s) { |buf|
        libuuid::uuid_unparse(uuid, buf);
    }
    s
}

#[doc = "Convert a string to a uuid"]
fn from_str(s: str) -> uuid {
    assert str::len(s) == 36u;

    let uuid = { a: 0u32, b: 0u32, c: 0u32, d: 0u32 };
    str::as_buf(s) { |buf|
        libuuid::uuid_parse(buf, uuid);
    }
    uuid
}

#[cfg(test)]
mod test {
    #[test]
    fn test() {
        uint::range(0u, 100000u) { |_i|
            let uuid = mk_uuid();
            assert uuid == from_str(to_str(uuid));

            let uuid = mk_uuid_random();
            assert uuid == from_str(to_str(uuid));

            let uuid = mk_uuid_time();
            assert uuid == from_str(to_str(uuid));
        }
    }
}
<commit_msg>Make rust-uuid portable to other *nixs.<commit_after>export uuid;
export uuid_random;
export uuid_time;
export to_str;
export from_str;

#[doc = "a uuid value"]
type uuid = {
    a: u32,
    b: u32,
    c: u32,
    d: u32,
};

#[cfg(target_os = "macos")]
#[nolink]
native mod uuid {
    fn uuid_generate(out: uuid);
    fn uuid_generate_random(out: uuid);
    fn uuid_generate_time(out: uuid);

    fn uuid_parse(s: *u8, uuid: uuid) -> libc::c_int;

    fn uuid_unparse(uuid: uuid, out: *u8);
    fn uuid_unparse_lower(uuid: uuid, out: *u8);
    fn uuid_unparse_upper(uuid: uuid, out: *u8);
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "freebsd")]
native mod uuid {
    fn uuid_generate(out: uuid);
    fn uuid_generate_random(out: uuid);
    fn uuid_generate_time(out: uuid);

    fn uuid_parse(s: *u8, uuid: uuid) -> libc::c_int;

    fn uuid_unparse(uuid: uuid, out: *u8);
    fn uuid_unparse_lower(uuid: uuid, out: *u8);
    fn uuid_unparse_upper(uuid: uuid, out: *u8);
}

#[doc = "Create a new uuid"]
fn uuid() -> uuid {
    let uuid = { a: 0u32, b: 0u32, c: 0u32, d: 0u32 };
    uuid::uuid_generate(uuid);
    uuid
}

#[doc = "Create a uuid from the current time and mac address"]
fn uuid_random() -> uuid {
    let uuid = { a: 0u32, b: 0u32, c: 0u32, d: 0u32 };
    uuid::uuid_generate_random(uuid);
    uuid
}

#[doc = "Create a uuid from a random number generator"]
fn uuid_time() -> uuid {
    let uuid = { a: 0u32, b: 0u32, c: 0u32, d: 0u32 };
    uuid::uuid_generate_time(uuid);
    uuid
}

#[doc = "Convert a uuid to a string"]
fn to_str(uuid: uuid) -> str {
    let mut s = "";
    str::reserve(s, 36u);
    unsafe { str::unsafe::set_len(s, 36u); }
    str::as_buf(s) { |buf|
        uuid::uuid_unparse(uuid, buf);
    }
    s
}

#[doc = "Convert a string to a uuid"]
fn from_str(s: str) -> uuid {
    assert str::len(s) == 36u;

    let uuid = { a: 0u32, b: 0u32, c: 0u32, d: 0u32 };
    str::as_buf(s) { |buf|
        uuid::uuid_parse(buf, uuid);
    }
    uuid
}

#[cfg(test)]
mod test {
    #[test]
    fn test() {
        uint::range(0u, 100000u) { |_i|
            let uuid = uuid();
            assert uuid == from_str(to_str(uuid));

            let uuid = uuid_random();
            assert uuid == from_str(to_str(uuid));

            let uuid = uuid_time();
            assert uuid == from_str(to_str(uuid));
        }
    }
}
<|endoftext|>


<commit_before>//! Generator of Rust-Qt crates.
//!
//! See [README](https://github.com/rust-qt/cpp_to_rust/tree/master/qt_generator/qt_generator)
//! for more information.

use crate::config::GlobalConfig;
use crate::processor;
use crate::workspace::Workspace;
use flexi_logger::{Duplicate, LevelFilter, LogSpecification, Logger};
use itertools::Itertools;
use log::{error, info};
use ritual_common::errors::{bail, err_msg, Result};
use ritual_common::file_utils::{canonicalize, create_dir, load_toml, path_to_str};
use ritual_common::target::current_target;
use std::path::PathBuf;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
/// Generates rust_qt crates using ritual.
/// See [ritual](https://github.com/rust-qt/ritual) for more details.
pub struct Options {
    #[structopt(parse(from_os_str))]
    /// Directory for output and temporary files
    pub workspace: PathBuf,
    #[structopt(long = "local-paths")]
    /// Write local paths to `ritual` crates in generated `Cargo.toml`
    pub local_paths: Option<bool>,
    #[structopt(short = "c", long = "crates", required = true)]
    /// Crates to process (e.g. `qt_core`)
    pub crates: Vec<String>,
    #[structopt(short = "o", long = "operations", required = true)]
    /// Operations to perform
    pub operations: Vec<String>,
    #[structopt(long = "cluster")]
    /// Cluster configuration
    pub cluster: Option<PathBuf>,
}

pub fn run_from_args(config: GlobalConfig) -> Result<()> {
    run(Options::from_args(), config)
}

pub fn run(options: Options, mut config: GlobalConfig) -> Result<()> {
    if !options.workspace.exists() {
        create_dir(&options.workspace)?;
    }
    let workspace_path = canonicalize(options.workspace)?;

    let mut workspace = Workspace::new(workspace_path.clone())?;

    Logger::with(LogSpecification::default(LevelFilter::Trace).build())
        .log_to_file()
        .directory(path_to_str(&workspace.log_path())?)
        .print_message()
        .duplicate_to_stderr(Duplicate::Info)
        .start()
        .unwrap_or_else(|e| panic!("Logger initialization failed: {}", e));

    info!("Workspace: {}", workspace_path.display());
    info!("Current target: {}", current_target().short_text());

    if let Some(local_paths) = options.local_paths {
        workspace.set_write_dependencies_local_paths(local_paths)?;
    }

    let mut was_any_action = false;

    let final_crates = if options.crates.iter().any(|x| *x == "all") {
        let all = config.all_crate_names();
        if all.is_empty() {
            bail!("\"all\" is not supported as crate name specifier");
        }
        all.to_vec()
    } else {
        options.crates.clone()
    };

    let operations = options
        .operations
        .iter()
        .map(|s| s.to_lowercase())
        .collect_vec();

    if operations.is_empty() {
        error!("No action requested. Run \"qt_generator --help\".");
        return Ok(());
    }

    for crate_name in &final_crates {
        let create_config = config
            .create_config_hook()
            .ok_or_else(|| err_msg("create_config_hook is missing"))?;

        let mut config = create_config(&crate_name)?;

        if let Some(cluster_config_path) = &options.cluster {
            config.set_cluster_config(load_toml(cluster_config_path)?);
        }

        was_any_action = true;
        processor::process(&mut workspace, &config, &operations)?;
    }

    //workspace.save_data()?;
    if was_any_action {
        info!("ritual finished");
    } else {
        error!("No action requested. Run \"qt_generator --help\".");
    }
    Ok(())
}
<commit_msg>use json for cluster config<commit_after>//! Generator of Rust-Qt crates.
//!
//! See [README](https://github.com/rust-qt/cpp_to_rust/tree/master/qt_generator/qt_generator)
//! for more information.

use crate::config::GlobalConfig;
use crate::processor;
use crate::workspace::Workspace;
use flexi_logger::{Duplicate, LevelFilter, LogSpecification, Logger};
use itertools::Itertools;
use log::{error, info};
use ritual_common::errors::{bail, err_msg, Result};
use ritual_common::file_utils::{canonicalize, create_dir, load_json, path_to_str};
use ritual_common::target::current_target;
use std::path::PathBuf;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
/// Generates rust_qt crates using ritual.
/// See [ritual](https://github.com/rust-qt/ritual) for more details.
pub struct Options {
    #[structopt(parse(from_os_str))]
    /// Directory for output and temporary files
    pub workspace: PathBuf,
    #[structopt(long = "local-paths")]
    /// Write local paths to `ritual` crates in generated `Cargo.toml`
    pub local_paths: Option<bool>,
    #[structopt(short = "c", long = "crates", required = true)]
    /// Crates to process (e.g. `qt_core`)
    pub crates: Vec<String>,
    #[structopt(short = "o", long = "operations", required = true)]
    /// Operations to perform
    pub operations: Vec<String>,
    #[structopt(long = "cluster")]
    /// Cluster configuration
    pub cluster: Option<PathBuf>,
}

pub fn run_from_args(config: GlobalConfig) -> Result<()> {
    run(Options::from_args(), config)
}

pub fn run(options: Options, mut config: GlobalConfig) -> Result<()> {
    if !options.workspace.exists() {
        create_dir(&options.workspace)?;
    }
    let workspace_path = canonicalize(options.workspace)?;

    let mut workspace = Workspace::new(workspace_path.clone())?;

    Logger::with(LogSpecification::default(LevelFilter::Trace).build())
        .log_to_file()
        .directory(path_to_str(&workspace.log_path())?)
        .print_message()
        .duplicate_to_stderr(Duplicate::Info)
        .start()
        .unwrap_or_else(|e| panic!("Logger initialization failed: {}", e));

    info!("Workspace: {}", workspace_path.display());
    info!("Current target: {}", current_target().short_text());

    if let Some(local_paths) = options.local_paths {
        workspace.set_write_dependencies_local_paths(local_paths)?;
    }

    let mut was_any_action = false;

    let final_crates = if options.crates.iter().any(|x| *x == "all") {
        let all = config.all_crate_names();
        if all.is_empty() {
            bail!("\"all\" is not supported as crate name specifier");
        }
        all.to_vec()
    } else {
        options.crates.clone()
    };

    let operations = options
        .operations
        .iter()
        .map(|s| s.to_lowercase())
        .collect_vec();

    if operations.is_empty() {
        error!("No action requested. Run \"qt_generator --help\".");
        return Ok(());
    }

    for crate_name in &final_crates {
        let create_config = config
            .create_config_hook()
            .ok_or_else(|| err_msg("create_config_hook is missing"))?;

        let mut config = create_config(&crate_name)?;

        if let Some(cluster_config_path) = &options.cluster {
            config.set_cluster_config(load_json(cluster_config_path)?);
        }

        was_any_action = true;
        processor::process(&mut workspace, &config, &operations)?;
    }

    //workspace.save_data()?;
    if was_any_action {
        info!("ritual finished");
    } else {
        error!("No action requested. Run \"qt_generator --help\".");
    }
    Ok(())
}
<|endoftext|>


<commit_before>use name_table::{NameTable};

use std::fmt;

pub type Predicate = usize;
pub type Constant = usize;
pub type Variable = usize;
pub type ClauseIndex = usize;

#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum Term {
    Constant(Constant),
    Variable(Variable),
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct Literal {
    pub predicate: Predicate,
    pub terms: Vec<Term>,
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct Clause {
    pub head: Option<Literal>,
    pub body: Vec<Literal>,
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct Fact {
    pub predicate: Predicate,
    pub terms: Vec<Constant>,
}

impl Clause {
    pub fn new_from_vec(head: Literal, body: Vec<Literal>) -> Self {
        Clause {
            head: Some(head),
            body: body,
        }
    }

    pub fn is_valid(&self) -> bool {
        for var in 0..self.num_variables() {
            if !self.contains_variable_in_body(var) {
                return false;
            }
        }
        return true;
    }

    pub fn num_variables(&self) -> usize {
        let mut count = 0;
        for lit in &self.body {
            for term in &lit.terms {
                if let &Term::Variable(var) = term {
                    if var + 1 > count {
                        count = var + 1;
                    }
                }
            }
        }
        return count;
    }

    pub fn contains_variable(&self, variable: Variable) -> bool {
        if let Some(ref head) = self.head {
            if head.contains_variable(variable) {
                return true;
            }
        }
        if self.contains_variable_in_body(variable) {
            return true;
        }
        return false;
    }

    pub fn contains_variable_in_body(&self, variable: Variable) -> bool {
        for lit in &self.body {
            if lit.contains_variable(variable) {
                return true;
            }
        }
        return false;
    }

    pub fn max_predicate(&self) -> Predicate {
        let mut max = 0;
        if let Some(ref head) = self.head {
            if head.predicate > max {
                max = head.predicate;
            }
        }
        for term in self.body.iter() {
            if term.predicate > max {
                max = term.predicate;
            }
        }
        return max;
    }
}

impl Literal {
    pub fn new_from_vec(predicate: Predicate, terms: Vec<Term>) -> Self {
        Literal {
            predicate: predicate,
            terms: terms,
        }
    }

    pub fn contains_variable(&self, variable: Variable) -> bool {
        for term in &self.terms {
            if let &Term::Variable(var) = term {
                if var == variable {
                    return true;
                }
            }
        }
        return false;
    }

    pub fn to_fact(self) -> Fact {
        let mut terms = Vec::new();
        for term in self.terms {
            match term {
                Term::Constant(cst) => {
                    terms.push(cst);
                },
                Term::Variable(_) => {
                    panic!("Literal::to_fact() called with Literal containing variables.");
                }
            }
        }
        Fact::new_from_vec(self.predicate, terms)
    }
}

impl Fact {
    pub fn new_from_vec(predicate: Predicate, terms: Vec<Constant>) -> Self {
        Fact {
            predicate: predicate,
            terms: terms,
        }
    }

    pub fn to_display<'a, 'b>(&'a self, pred_names: &'b NameTable) -> FactDisplayer<'a, 'b> {
        FactDisplayer {
            fact: self,
            name: pred_names.get_name(self.predicate).unwrap(),
        }
    }
}

pub struct FactDisplayer<'a, 'b> {
    fact: &'a Fact,
    name: &'b str,
}

impl<'a, 'b> fmt::Display for FactDisplayer<'a, 'b> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{}(", self.name);
        let num_terms = self.fact.terms.len();
        for (i, term) in self.fact.terms.iter().enumerate() {
            if i + 1 == num_terms {
                write!(f, "{}", term);
            } else {
                write!(f, "{}, ", term);
            }
        }
        write!(f, ").");
        return Ok(());
    }
}
<commit_msg>Fix a few ignored errors when writing to a string.<commit_after>use name_table::{NameTable};

use std::fmt;

pub type Predicate = usize;
pub type Constant = usize;
pub type Variable = usize;
pub type ClauseIndex = usize;

#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum Term {
    Constant(Constant),
    Variable(Variable),
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct Literal {
    pub predicate: Predicate,
    pub terms: Vec<Term>,
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct Clause {
    pub head: Option<Literal>,
    pub body: Vec<Literal>,
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct Fact {
    pub predicate: Predicate,
    pub terms: Vec<Constant>,
}

impl Clause {
    pub fn new_from_vec(head: Literal, body: Vec<Literal>) -> Self {
        Clause {
            head: Some(head),
            body: body,
        }
    }

    pub fn is_valid(&self) -> bool {
        for var in 0..self.num_variables() {
            if !self.contains_variable_in_body(var) {
                return false;
            }
        }
        return true;
    }

    pub fn num_variables(&self) -> usize {
        let mut count = 0;
        for lit in &self.body {
            for term in &lit.terms {
                if let &Term::Variable(var) = term {
                    if var + 1 > count {
                        count = var + 1;
                    }
                }
            }
        }
        return count;
    }

    pub fn contains_variable(&self, variable: Variable) -> bool {
        if let Some(ref head) = self.head {
            if head.contains_variable(variable) {
                return true;
            }
        }
        if self.contains_variable_in_body(variable) {
            return true;
        }
        return false;
    }

    pub fn contains_variable_in_body(&self, variable: Variable) -> bool {
        for lit in &self.body {
            if lit.contains_variable(variable) {
                return true;
            }
        }
        return false;
    }

    pub fn max_predicate(&self) -> Predicate {
        let mut max = 0;
        if let Some(ref head) = self.head {
            if head.predicate > max {
                max = head.predicate;
            }
        }
        for term in self.body.iter() {
            if term.predicate > max {
                max = term.predicate;
            }
        }
        return max;
    }
}

impl Literal {
    pub fn new_from_vec(predicate: Predicate, terms: Vec<Term>) -> Self {
        Literal {
            predicate: predicate,
            terms: terms,
        }
    }

    pub fn contains_variable(&self, variable: Variable) -> bool {
        for term in &self.terms {
            if let &Term::Variable(var) = term {
                if var == variable {
                    return true;
                }
            }
        }
        return false;
    }

    pub fn to_fact(self) -> Fact {
        let mut terms = Vec::new();
        for term in self.terms {
            match term {
                Term::Constant(cst) => {
                    terms.push(cst);
                },
                Term::Variable(_) => {
                    panic!("Literal::to_fact() called with Literal containing variables.");
                }
            }
        }
        Fact::new_from_vec(self.predicate, terms)
    }
}

impl Fact {
    pub fn new_from_vec(predicate: Predicate, terms: Vec<Constant>) -> Self {
        Fact {
            predicate: predicate,
            terms: terms,
        }
    }

    pub fn to_display<'a, 'b>(&'a self, pred_names: &'b NameTable) -> FactDisplayer<'a, 'b> {
        FactDisplayer {
            fact: self,
            name: pred_names.get_name(self.predicate).unwrap(),
        }
    }
}

pub struct FactDisplayer<'a, 'b> {
    fact: &'a Fact,
    name: &'b str,
}

impl<'a, 'b> fmt::Display for FactDisplayer<'a, 'b> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{}(", self.name)?;
        let num_terms = self.fact.terms.len();
        for (i, term) in self.fact.terms.iter().enumerate() {
            if i + 1 == num_terms {
                write!(f, "{}", term)?;
            } else {
                write!(f, "{}, ", term)?;
            }
        }
        write!(f, ").")?;
        return Ok(());
    }
}
<|endoftext|>


<commit_before>extern crate "parser-combinators" as parser_combinators;
use self::parser_combinators::{between, spaces, many, satisfy, Parser, ParserExt, ParseResult};
use self::parser_combinators::primitives::{State, Stream};
use super::ast::*;
use super::ast::ExprNode::*;

pub fn name<I>(input: State<I>) -> ParseResult<NameNode, I>
    where I: Stream<Item=char> {
         let ident_start = satisfy(|c|
            c.is_alphabetic()
                || c == '='
                || c == '*'
                || c == '+'
                || c == '/'
                || c == '!'
                || c == '\\'
                || c == '?');
        let ident_body = satisfy(|c|
            c.is_alphanumeric()
                || c == '='
                || c == '*'
                || c == '+'
                || c == '/'
                || c == '!'
                || c == '\\'
                || c == '?');
        ident_start
            .and(many::<Vec<_>, _>(ident_body).map(|it|
                it.iter().fold(
                    String::new(),
                    |mut s: String, i| {
                        s.push(*i);
                        s
                    }
                    )
                ))
            .parse_state(input)
            .map(|x| {
                let mut s = String::new();
                s.push((x.0).0);
                s.push_str(&(x.0).1);
                (NameNode{ name: s}, x.1)
            })
}

pub fn expr<I>(input: State<I>) -> ParseResult<ExprNode, I>
    where I: Stream<Item=char> {
        let spaces = spaces();
        let sexpr = between(
            satisfy(|c| c == '('),
            satisfy(|c| c == ')'),
            (name as fn(_) -> _)
                .and(many(expr as fn(_) -> _))
                .map(|x| {
                    SExpr(SExprNode {
                        operator: x.0,
                        operands: (x.1)
                    })
                })
                );
        spaces.clone().with(
            sexpr
                .or((name as fn(_) -> _).map(Name))
            ).parse_state(input)
}

#[cfg(test)]
mod tests {
    use ::ast::*;
    use ::ast::ExprNode::*;
    use super::expr;
    use super::parser_combinators::Parser;

    #[test]
    fn test_basic_ident() {
        assert_eq!(
            (expr as fn (_) -> _).parse("ident").unwrap(),
            (Name(NameNode { name: "ident".to_string() }), "")
            );
    }

        #[test]
    fn test_basic_sexpr() {
        assert_eq!(
            (expr as fn (_) -> _).parse("(ident arg1 arg2)").unwrap(),
            (SExpr(SExprNode {
                operator: NameNode { name: "ident".to_string() },
                operands: vec![
                    Name(NameNode { name: "arg1".to_string() }),
                    Name(NameNode { name: "arg2".to_string() })
                ]
            }), "")
            );
    }

}
<commit_msg>Added comments & tests<commit_after>extern crate "parser-combinators" as parser_combinators;
use self::parser_combinators::{between, spaces, many, satisfy, Parser, ParserExt, ParseResult};
use self::parser_combinators::primitives::{State, Stream};
use super::ast::*;
use super::ast::ExprNode::*;

/// Parses valid Scheme identifiers.
///
/// A Scheme identifier should begin with a letter or the characters
/// `=`, `*`, `+`, `/`,`!`,`\`,or `?`. That character may then be
/// followed by any number of letters,numbers, or the above characters.
/// I don't know why `_` isn't allowed, either.
///
/// Essentially, it should match the regex
/// `[a-zA-Z=\*\+\/\!\/\?][a-zA-Z0-9=\*\+\/\!\/\?]*`/
pub fn name<I>(input: State<I>) -> ParseResult<NameNode, I>
    where I: Stream<Item=char> {
         let ident_start = satisfy(|c|
            c.is_alphabetic()
                || c == '='
                || c == '*'
                || c == '+'
                || c == '/'
                || c == '!'
                || c == '\\'
                || c == '?');
        let ident_body = satisfy(|c|
            c.is_alphanumeric()
                || c == '='
                || c == '*'
                || c == '+'
                || c == '/'
                || c == '!'
                || c == '\\'
                || c == '?');
        ident_start
            .and(many::<Vec<_>, _>(ident_body).map(|it|
                it.iter().fold(
                    String::new(),
                    |mut s: String, i| {
                        s.push(*i);
                        s
                    }
                    )
                ))
            .parse_state(input)
            .map(|x| {
                let mut s = String::new();
                s.push((x.0).0);
                s.push_str(&(x.0).1);
                (NameNode{ name: s}, x.1)
            })
}

/// Parser for expressions.
/// Basically this just strings together all the subparsers
/// for expression types.
pub fn expr<I>(input: State<I>) -> ParseResult<ExprNode, I>
    where I: Stream<Item=char> {
        let spaces = spaces();
        let sexpr = between(
            satisfy(|c| c == '('),
            satisfy(|c| c == ')'),
            (name as fn(_) -> _)
                .and(many(expr as fn(_) -> _))
                .map(|x| {
                    SExpr(SExprNode {
                        operator: x.0,
                        operands: (x.1)
                    })
                })
                );
        spaces.clone().with(
            sexpr
                .or((name as fn(_) -> _).map(Name))
            ).parse_state(input)
}

#[cfg(test)]
mod tests {
    use ::ast::*;
    use ::ast::ExprNode::*;
    use super::expr;
    use super::parser_combinators::Parser;

    #[test]
    fn test_parse_ident() {
        assert_eq!(
            (expr as fn (_) -> _).parse("ident").unwrap(),
            (Name(NameNode { name: "ident".to_string() }), "")
            );
        assert_eq!(
            (expr as fn (_) -> _).parse("a").unwrap(),
            (Name(NameNode { name: "a".to_string() }), "")
            );
        assert_eq!(
            (expr as fn (_) -> _).parse("ident=With\\special!Chars").unwrap(),
            (Name(NameNode { name: "ident=With\\special!Chars".to_string() }), "")
            );/*
        assert_eq!(
            (expr as fn (_) -> _).parse("12thisIsWrong"),
            (Err(_),"")
            )*/
    }

        #[test]
    fn test_basic_sexpr() {
        assert_eq!(
            (expr as fn (_) -> _).parse("(ident arg1 arg2)").unwrap(),
            (SExpr(SExprNode {
                operator: NameNode { name: "ident".to_string() },
                operands: vec![
                    Name(NameNode { name: "arg1".to_string() }),
                    Name(NameNode { name: "arg2".to_string() })
                ]
            }), "")
            );
    }

}
<|endoftext|>


<commit_before>//! OpenGL back-end for Rust-Graphics.

// External crates.
use gl = opengles::gl2;
use shader_utils::{with_shader_source, compile_shader};
use BackEnd = graphics::BackEnd;

// Local crate.
use AssetStore = asset_store::AssetStore;

static VERTEX_SHADER_TRI_LIST_XY_RGBA: &'static str = "
attribute vec4 a_v4Position;
attribute vec4 a_v4FillColor;

varying vec4 v_v4FillColor;

void main()
{
    v_v4FillColor = a_v4FillColor;
    gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA: &'static str = "
varying vec4 v_v4FillColor;

void main()
{
        gl_FragColor = v_v4FillColor;
}
";

/// OpenGL back-end for Rust-Graphics.
pub struct Gl<'a> {
    gl_data: &'a GlData,
    asset_store: &'a AssetStore,
}

impl<'a> Gl<'a> {
    /// Creates a new OpenGl back-end.
    pub fn new(
        gl_data: &'a GlData,
        asset_store: &'a AssetStore
    ) -> Gl<'a> {
        Gl {
            gl_data: gl_data,
            asset_store: asset_store,
        }
    }
}

/// Contains OpenGL data.
pub struct GlData {
    vertex_shader: gl::GLuint,
    fragment_shader: gl::GLuint,
    program: gl::GLuint,
    a_v4Position: gl::GLuint,
    a_v4FillColor: gl::GLuint,
    position_id: gl::GLuint,
    fill_color_id: gl::GLuint,
}

impl<'a> GlData {
    /// Creates a new OpenGl back-end.
    pub fn new() -> GlData {
        let vertex_shader = with_shader_source(
            VERTEX_SHADER_TRI_LIST_XY_RGBA, |src| {
                compile_shader(gl::VERTEX_SHADER, src)
            }).unwrap();
        let fragment_shader = with_shader_source(
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA, |src| {
                compile_shader(gl::FRAGMENT_SHADER, src)
            }).unwrap();
        let program = gl::create_program();
        gl::attach_shader(program, vertex_shader);
        gl::attach_shader(program, fragment_shader);
        gl::link_program(program);
        gl::use_program(program);
        let a_v4Position =
            gl::get_attrib_location(program, "a_v4Position") as gl::GLuint;
        gl::enable_vertex_attrib_array(a_v4Position);
        let a_v4FillColor =
            gl::get_attrib_location(program, "a_v4FillColor") as gl::GLuint;
        gl::enable_vertex_attrib_array(a_v4FillColor);

        // Load the vertices and color buffers.
        let buffers = gl::gen_buffers(2);
        let position_id = *buffers.get(0);
        let fill_color_id = *buffers.get(1);

        GlData {
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            a_v4Position: a_v4Position,
            a_v4FillColor: a_v4FillColor,
            position_id: position_id,
            fill_color_id: fill_color_id,
        }
    }
}

impl<'a> BackEnd for Gl<'a> {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        gl::clear_color(r, g, b, a);
        gl::clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
    }

    fn enable_alpha_blend(&mut self) {
        gl::enable(gl::BLEND);
        gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
    }

    fn disable_alpha_blend(&mut self) {
        gl::disable(gl::BLEND);
    }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        let data = self.gl_data;
        let size_vertices: i32 = 2;
        gl::bind_buffer(
            gl::ARRAY_BUFFER, data.position_id);
        gl::buffer_data(
            gl::ARRAY_BUFFER, vertices.as_slice(), gl::DYNAMIC_DRAW);
        gl::vertex_attrib_pointer_f32(
            data.a_v4Position, size_vertices, true, 0, 0);

        gl::bind_buffer(
            gl::ARRAY_BUFFER, data.fill_color_id);
        gl::buffer_data(
            gl::ARRAY_BUFFER, colors.as_slice(), gl::DYNAMIC_DRAW);
        gl::vertex_attrib_pointer_f32(
            data.a_v4FillColor, 4, false, 0, 0);

        // gl::enable(gl::DEPTH_TEST);
        gl::cull_face(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::draw_arrays(gl::TRIANGLES, 0, items);
    }
}

<commit_msg>Added texture shaders<commit_after>//! OpenGL back-end for Rust-Graphics.

// External crates.
use gl = opengles::gl2;
use shader_utils::{with_shader_source, compile_shader};
use BackEnd = graphics::BackEnd;

// Local crate.
use AssetStore = asset_store::AssetStore;

static VERTEX_SHADER_TRI_LIST_XY_RGBA: &'static str = "
attribute vec4 a_v4Position;
attribute vec4 a_v4FillColor;

varying vec4 v_v4FillColor;

void main()
{
    v_v4FillColor = a_v4FillColor;
    gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA: &'static str = "
varying vec4 v_v4FillColor;

void main()
{
        gl_FragColor = v_v4FillColor;
}
";

static VERTEX_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
attribute vec4 a_v4Position;
attribute vec4 a_v4FillColor;
attribute vec2 a_v2TexCoord;

uniform sampler2D s_texture;

varying vec2 v_v2TexCoord;
varying vec4 v_v4FillColor;

void main()
{
        v_v2TexCoord = a_v2TexCoord;
        v_v4FillColor = a_v4FillColor;
        gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
uniform sampler2D s_texture;

varying vec2 v_v2TexCoord;
varying vec4 v_v4FillColor;

void main()
{
        gl_FragColor = texture2D(s_texture, v_v2TexCoord) * v_v4FillColor;
}
";

/// OpenGL back-end for Rust-Graphics.
pub struct Gl<'a> {
    gl_data: &'a GlData,
    asset_store: &'a AssetStore,
}

impl<'a> Gl<'a> {
    /// Creates a new OpenGl back-end.
    pub fn new(
        gl_data: &'a GlData,
        asset_store: &'a AssetStore
    ) -> Gl<'a> {
        Gl {
            gl_data: gl_data,
            asset_store: asset_store,
        }
    }
}

struct TriListXYRGBA {
    vertex_shader: gl::GLuint,
    fragment_shader: gl::GLuint,
    program: gl::GLuint,
    a_v4Position: gl::GLuint,
    a_v4FillColor: gl::GLuint,
}

impl TriListXYRGBA {
    fn new() -> TriListXYRGBA {
        let vertex_shader = with_shader_source(
            VERTEX_SHADER_TRI_LIST_XY_RGBA, |src| {
                compile_shader(gl::VERTEX_SHADER, src)
            }).unwrap();
        let fragment_shader = with_shader_source(
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA, |src| {
                compile_shader(gl::FRAGMENT_SHADER, src)
            }).unwrap();
        let program = gl::create_program();
        gl::attach_shader(program, vertex_shader);
        gl::attach_shader(program, fragment_shader);
        gl::link_program(program);
        gl::use_program(program);
        let a_v4Position = gl::get_attrib_location(
            program, "a_v4Position") as gl::GLuint;
        gl::enable_vertex_attrib_array(a_v4Position);
        let a_v4FillColor = gl::get_attrib_location(
            program, "a_v4FillColor") as gl::GLuint;
        gl::enable_vertex_attrib_array(a_v4FillColor);
        TriListXYRGBA {
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            a_v4Position: a_v4Position,
            a_v4FillColor: a_v4FillColor,
        }
    }
}

struct TriListXYRGBAUV {
    vertex_shader: gl::GLuint,
    fragment_shader: gl::GLuint,
    program: gl::GLuint,
    a_v4Position: gl::GLuint,
    a_v4FillColor: gl::GLuint,
    a_v2TexCoord: gl::GLuint,
}

impl TriListXYRGBAUV {
    fn new() -> TriListXYRGBAUV {
        let vertex_shader = with_shader_source(
            VERTEX_SHADER_TRI_LIST_XY_RGBA_UV, |src| {
                compile_shader(gl::VERTEX_SHADER, src)
            }).unwrap();
        let fragment_shader = with_shader_source(
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV, |src| {
                compile_shader(gl::FRAGMENT_SHADER, src)
            }).unwrap();
        let program = gl::create_program();
        gl::attach_shader(program, vertex_shader);
        gl::attach_shader(program, fragment_shader);
        gl::link_program(program);
        gl::use_program(program);
        let a_v4Position = gl::get_attrib_location(
            program, "a_v4Position") as gl::GLuint;
        gl::enable_vertex_attrib_array(a_v4Position);
        let a_v4FillColor = gl::get_attrib_location(
            program, "a_v4FillColor") as gl::GLuint;
        gl::enable_vertex_attrib_array(a_v4FillColor);
        let a_v2TexCoord = gl::get_attrib_location(
            program, "a_v2TexCoord") as gl::GLuint;
        TriListXYRGBAUV {
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            a_v4Position: a_v4Position,
            a_v4FillColor: a_v4FillColor,
            a_v2TexCoord: a_v2TexCoord,
        }
    }
}

/// Contains OpenGL data.
pub struct GlData {
    tri_list_xy_rgba: TriListXYRGBA,
    tri_list_xy_rgba_uv: TriListXYRGBAUV,
    // id of buffer for xy positions.
    position_id: gl::GLuint,
    // id of buffer for rgba colors.
    fill_color_id: gl::GLuint,
    // id of buffer for uv texture coords.
    tex_coord_id: gl::GLuint,
}

impl<'a> GlData {
    /// Creates a new OpenGl back-end.
    pub fn new() -> GlData {
        // Load the vertices, color and texture coord buffers.
        let buffers = gl::gen_buffers(3);
        let position_id = *buffers.get(0);
        let fill_color_id = *buffers.get(1);
        let tex_coord_id = *buffers.get(2);

        GlData {
            tri_list_xy_rgba: TriListXYRGBA::new(),
            tri_list_xy_rgba_uv: TriListXYRGBAUV::new(),
            position_id: position_id,
            fill_color_id: fill_color_id,
            tex_coord_id: tex_coord_id,
        }
    }
}

impl<'a> BackEnd for Gl<'a> {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        gl::clear_color(r, g, b, a);
        gl::clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
    }

    fn enable_alpha_blend(&mut self) {
        gl::enable(gl::BLEND);
        gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
    }

    fn disable_alpha_blend(&mut self) {
        gl::disable(gl::BLEND);
    }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        let data = &self.gl_data;
        let shader = &data.tri_list_xy_rgba;
        let size_vertices: i32 = 2;
        gl::bind_buffer(
            gl::ARRAY_BUFFER, data.position_id);
        gl::buffer_data(
            gl::ARRAY_BUFFER, vertices.as_slice(), gl::DYNAMIC_DRAW);
        gl::vertex_attrib_pointer_f32(
            shader.a_v4Position, size_vertices, true, 0, 0);

        gl::bind_buffer(
            gl::ARRAY_BUFFER, data.fill_color_id);
        gl::buffer_data(
            gl::ARRAY_BUFFER, colors.as_slice(), gl::DYNAMIC_DRAW);
        gl::vertex_attrib_pointer_f32(
            shader.a_v4FillColor, 4, false, 0, 0);

        // gl::enable(gl::DEPTH_TEST);
        gl::cull_face(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::draw_arrays(gl::TRIANGLES, 0, items);
    }
}

<|endoftext|>