//! returns: 0
fn memEq(a: *[u8], b: *[u8]) -> bool {
    if a.len <> b.len {
        return false;
    }
    for i in 0..a.len {
        if a[i] <> b[i] {
            return false;
        }
    }
    return true;
}

fn sliceU8(input: *[u8]) -> *[u8] {
    return input;
}

fn sliceI32(input: *[i32]) -> *[i32] {
    return input;
}

fn sliceEqualU32(a: *[u32], b: *[u32]) -> bool {
    if a.len <> b.len {
        return false;
    }
    for i in 0..a.len {
        if a[i] <> b[i] {
            return false;
        }
    }
    return true;
}

fn sliceEqualI32(a: *[i32], b: *[i32]) -> bool {
    if a.len <> b.len {
        return false;
    }
    for i in 0..a.len {
        if a[i] <> b[i] {
            return false;
        }
    }
    return true;
}

fn sliceEqual1() -> bool {
    let a1: [u32; 3] = [9, 42, 3];

    let s1: *[u32] = &a1[..];
    let s2: *[u32] = &a1[..];

    return s1 == s2 and sliceEqualU32(s1, s2);
}

fn sliceEqual2() -> bool {
    let a1: [u32; 3] = [9, 42, 3];

    let s1: *[u32] = &a1[1..];
    let s2: *[u32] = &a1[1..];

    return s1 == s2 and sliceEqualU32(s1, s2);
}

fn sliceEqual3() -> bool {
    let a1: [u32; 3] = [9, 42, 3];

    let s1: *[u32] = &a1[..1];
    let s2: *[u32] = &a1[..1];

    return s1 == s2 and sliceEqualU32(s1, s2);
}

fn sliceEqual4() -> bool {
    let a1: [u32; 3] = [9, 42, 3];

    let s1: *[u32] = &a1[2..];
    let s2: *[u32] = &a1[2..];

    return s1 == s2 and sliceEqualU32(s1, s2);
}

fn sliceNotEqualSameArray1() -> bool {
    let a1: [u32; 3] = [42, 8, 3];

    let s1: *[u32] = &a1[..2];
    let s2: *[u32] = &a1[1..3];

    return s1 <> s2 and not sliceEqualU32(s1, s2);
}

fn sliceNotEqualSameArray2() -> bool {
    let a1: [u32; 3] = [42, 8, 3];

    let s1: *[u32] = &a1[..2];
    let s2: *[u32] = &a1[..3];

    return s1 <> s2 and not sliceEqualU32(s1, s2);
}

fn sliceEqualDifferentArray() -> bool {
    let a1: [u32; 3] = [42, 8, 3];
    let a2: [u32; 3] = [42, 8, 3];

    let s1: *[u32] = &a1[..];
    let s2: *[u32] = &a2[..];

    return sliceEqualU32(s1, s2) and s1 <> s2;
}

fn sliceEqualString1() -> bool {
    let s1: *[u8] = "ABC";
    let s2: *[u8] = "ABC";

    return memEq(s1, s2);
}

fn sliceEqualString2() -> bool {
    let s1: *[u8] = "ABC";
    let s2: *[u8] = "DEF";

    return not memEq(s1, s2);
}

fn sliceEqualString3() -> bool {
    let a1: [u8; 3] = ['A', 'B', 'C'];
    let s1: *[u8] = &a1[..];
    let s2: *[u8] = "ABC";

    return memEq(s1, s2)
       and memEq(s1, "ABC")
       and memEq(&a1[..], "ABC");
}

fn sliceEqualString4() -> bool {
    let s1: *[u8] = "ABC";
    let s2: *[u8] = &['A', 'B', 'C'];

    return memEq(s1, s2);
}

fn sliceEqualString5() -> bool {
    let s1: *[u8] = "ABC";

    // Sub-slicing a slice currently trips a separate compiler bug.
    // Keep this check focused on slice equality behavior itself.
    return memEq(s1, "ABC");
}

fn sliceNotEqualU8() -> bool {
    let a: [u8; 3] = [1, 2, 3];
    let b: [u8; 3] = [1, 2, 4];
    let s: *[u8] = &[1, 2, 3];

    return not memEq(s, &[1, 2, 4])
       and not memEq(s, &[1, 0, 3])
       and not memEq("ABC", "ABCD")
       and not memEq("ABC", "ABD")
       and not memEq(&a[..], &a[1..])
       and not memEq(&a[..], &b[..])
       and not memEq(&a[..], &[1, 3, 3]);
}

fn sliceNotEqualU16() -> bool {
    let a: [u16; 3] = [1, 2, 3];
    let b: [u16; 3] = [1, 2, 4];
    let s: *[u16] = &[1, 2, 3];

    return s <> &[1, 2, 4]
       and s <> &[1, 0, 3]
       and &a[..] <> &a[1..]
       and &a[..] <> &b[..]
       and &a[..] <> &[1, 3, 3];
}

fn sliceReturnEqual() -> bool {
    return memEq(sliceU8("ABC"), "ABC")
       and sliceEqualI32(sliceI32(&[1, 2, 3]), &[1, 2, 3]);
}

@default fn main() -> i32 {
    assert sliceEqual1();
    assert sliceEqual2();
    assert sliceEqual3();
    assert sliceEqual4();
    assert sliceEqualString1();
    assert sliceEqualString2();
    assert sliceEqualString3();
    assert sliceEqualString4();
    assert sliceEqualString5();
    assert sliceNotEqualSameArray1();
    assert sliceNotEqualSameArray2();
    assert sliceEqualDifferentArray();
    assert sliceNotEqualU8();
    assert sliceNotEqualU16();
    assert sliceReturnEqual();

    return 0;
}
