diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..2fe8eb0 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,84 @@ +name: Tests + +on: [push, pull_request] + +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: true + matrix: + include: + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + toolchain: stable + - os: macos-latest + target: x86_64-apple-darwin + toolchain: stable + - os: windows-latest + target: x86_64-pc-windows-gnu + toolchain: stable + - os: windows-latest + target: x86_64-pc-windows-msvc + toolchain: beta + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + toolchain: 1.42.0 # MSRV + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + toolchain: nightly + - os: ubuntu-latest + deps: sudo apt install gcc-multilib + target: i686-unknown-linux-gnu + toolchain: nightly + + steps: + - uses: actions/checkout@v2 + - name: Install toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + target: ${{ matrix.target }} + toolchain: ${{ matrix.toolchain }} + override: true + - run: ${{ matrix.deps }} + - name: Test sailfish + run: | + cargo test --target ${{ matrix.target }} --manifest-path sailfish/Cargo.toml --no-default-features + cargo test --target ${{ matrix.target }} --manifest-path sailfish/Cargo.toml --all-features + - name: Test sailfish-compiler + run: | + cargo test --target ${{ matrix.target }} --manifest-path sailfish-compiler/Cargo.toml + - name: Integration tests + # Currently integration tests have some issue related to line feeds + if: ${{ matrix.os != 'windows-latest' }} + run: | + cargo test --target ${{ matrix.target }} --manifest-path sailfish-tests/integration-tests/Cargo.toml + + test-miri: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install toolchain + run: | + MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri) + rustup default "$MIRI_NIGHTLY" + rustup component add miri + - name: Test sailfish + run: | + cargo miri test --manifest-path sailfish/Cargo.toml --no-default-features + cargo miri test --manifest-path sailfish/Cargo.toml --all-features + + test-ios: + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + - name: Install toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly + target: aarch64-apple-ios + override: true + - name: Build only + run: cargo build --target=aarch64-apple-ios --workspace diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 44ffad3..0000000 --- a/.travis.yml +++ /dev/null @@ -1,29 +0,0 @@ -dist: bionic -language: rust - -branches: - except: - - stable - -matrix: - fast_finish: true - include: - - os: linux - rust: stable - - - os: linux - rust: nightly - - # minimum supported version - - os: linux - rust: 1.42.0 - - - os: osx - rust: stable - -env: - global: - - RUST_BACKTRACE=1 - -script: - - bash ./scripts/travis.sh diff --git a/README.md b/README.md index 833fca6..8fd44c0 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,7 @@ Simple, small, and extremely fast template engine for Rust -[![Build Status](https://travis-ci.org/Kogia-sima/sailfish.svg?branch=master)](https://travis-ci.org/Kogia-sima/sailfish) -[![Build status](https://ci.appveyor.com/api/projects/status/fa3et4rft4dyvdn9/branch/master?svg=true)](https://ci.appveyor.com/project/Kogiasima/sailfish/branch/master) +[![Tests](https://github.com/Kogia-sima/sailfish/workflows/Tests/badge.svg)](https://github.com/Kogia-sima/sailfish/actions?query=workflow%3ATests) [![Version](https://img.shields.io/crates/v/sailfish)](https://crates.io/crates/sailfish) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/Kogia-sima/sailfish/blob/master/LICENSE) diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index e7b953a..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,28 +0,0 @@ -platform: - - x64 - -environment: - matrix: - - RUST_VERSION: stable - PLATFORM_TARGET: x86_64 - PLATFORM_VS: x64 - -install: - # Install Rust. - - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - - rustup-init.exe -yv --default-toolchain %RUST_VERSION% --default-host x86_64-pc-windows-msvc - - set PATH=%USERPROFILE%\.cargo\bin;%PATH% - - rustc -vV - - cargo -vV - -build_script: - - cargo build --all-features -p sailfish -p sailfish-compiler - -test_script: - - cargo test --all-features -p sailfish -p sailfish-compiler -p integration-tests - -notifications: - - provider: Email - on_build_success: false - on_build_failure: false - on_build_status_changed: false diff --git a/sailfish/src/runtime/escape/mod.rs b/sailfish/src/runtime/escape/mod.rs index c7d4b64..2758af8 100644 --- a/sailfish/src/runtime/escape/mod.rs +++ b/sailfish/src/runtime/escape/mod.rs @@ -2,20 +2,8 @@ //! //! By default sailfish replaces the characters `&"'<>` with the equivalent html. -#![cfg_attr(target_feature = "avx2", allow(dead_code))] - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -mod avx2; mod fallback; mod naive; -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -mod sse2; - -use std::sync::atomic::{AtomicPtr, Ordering}; - -use super::buffer::Buffer; - -type FnRaw = *mut (); static ESCAPE_LUT: [u8; 256] = [ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, @@ -33,55 +21,77 @@ static ESCAPE_LUT: [u8; 256] = [ const ESCAPED: [&str; 5] = [""", "&", "'", "<", ">"]; const ESCAPED_LEN: usize = 5; -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -static FN: AtomicPtr<()> = AtomicPtr::new(escape as FnRaw); +#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), not(miri)))] +macro_rules! generate_impl { + () => { + mod avx2; + mod sse2; -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -fn escape(feed: &str, buf: &mut Buffer) { - debug_assert!(feed.len() >= 16); - let fun = if is_x86_feature_detected!("avx2") { - avx2::escape - } else if is_x86_feature_detected!("sse2") { - sse2::escape - } else { - fallback::escape - }; + use super::buffer::Buffer; + use std::sync::atomic::{AtomicPtr, Ordering}; - FN.store(fun as FnRaw, Ordering::Relaxed); - unsafe { fun(feed, buf) }; -} + type FnRaw = *mut (); -/// write the escaped contents into `Buffer` -#[cfg_attr(feature = "perf-inline", inline)] -pub fn escape_to_buf(feed: &str, buf: &mut Buffer) { - unsafe { - if feed.len() < 16 { - buf.reserve_small(feed.len() * 6); - let l = naive::escape_small(feed, buf.as_mut_ptr().add(buf.len())); - buf.advance(l); - } else { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - { - #[cfg(target_feature = "avx2")] - { + static FN: AtomicPtr<()> = AtomicPtr::new(escape as FnRaw); + + fn escape(feed: &str, buf: &mut Buffer) { + debug_assert!(feed.len() >= 16); + let fun = if is_x86_feature_detected!("avx2") { + avx2::escape + } else if is_x86_feature_detected!("sse2") { + sse2::escape + } else { + fallback::escape + }; + + FN.store(fun as FnRaw, Ordering::Relaxed); + unsafe { fun(feed, buf) }; + } + + /// write the escaped contents into `Buffer` + #[cfg_attr(feature = "perf-inline", inline)] + pub fn escape_to_buf(feed: &str, buf: &mut Buffer) { + unsafe { + if feed.len() < 16 { + buf.reserve_small(feed.len() * 6); + let l = naive::escape_small(feed, buf.as_mut_ptr().add(buf.len())); + buf.advance(l); + } else if cfg!(target_feature = "avx2") { avx2::escape(feed, buf); - } - - #[cfg(not(target_feature = "avx2"))] - { + } else { let fun = FN.load(Ordering::Relaxed); std::mem::transmute::(fun)(feed, buf); } } + } + }; +} - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] - { - fallback::escape(feed, buf); +#[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), not(miri))))] +macro_rules! generate_impl { + () => { + use super::buffer::Buffer; + + #[cfg_attr(feature = "perf-inline", inline)] + pub fn escape_to_buf(feed: &str, buf: &mut Buffer) { + unsafe { + if cfg!(miri) { + let bp = feed.as_ptr(); + naive::escape(buf, bp, bp, bp.add(feed.len())) + } else if feed.len() < 16 { + buf.reserve_small(feed.len() * 6); + let l = naive::escape_small(feed, buf.as_mut_ptr().add(buf.len())); + buf.advance(l); + } else { + fallback::escape(feed, buf) + } } } - } + }; } +generate_impl!(); + /// write the escaped contents into `String` /// /// # Examples @@ -153,6 +163,7 @@ mod tests { } #[test] + #[cfg(not(miri))] fn random() { const ASCII_CHARS: &'static [u8] = br##"abcdefghijklmnopqrstuvwxyz0123456789-^\@[;:],./\!"#$%&'()~=~|`{+*}<>?_"##; let mut state = 88172645463325252u64; @@ -184,21 +195,23 @@ mod tests { s.as_ptr().add(s.len()), ); - dbg!(s); fallback::escape(s, &mut buf); assert_eq!(buf.as_str(), buf_naive.as_str()); buf.clear(); - if is_x86_feature_detected!("sse2") { - sse2::escape(s, &mut buf); - assert_eq!(buf.as_str(), buf_naive.as_str()); - buf.clear(); - } + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + { + if is_x86_feature_detected!("sse2") { + sse2::escape(s, &mut buf); + assert_eq!(buf.as_str(), buf_naive.as_str()); + buf.clear(); + } - if is_x86_feature_detected!("avx2") { - avx2::escape(s, &mut buf); - assert_eq!(buf.as_str(), buf_naive.as_str()); - buf.clear(); + if is_x86_feature_detected!("avx2") { + avx2::escape(s, &mut buf); + assert_eq!(buf.as_str(), buf_naive.as_str()); + buf.clear(); + } } }