Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ jobs:
echo "${{ matrix.core }} archive: $n ray_dfd_check_live symbols, as expected"

- name: Test
env:
RUST_TEST_THREADS: 1
run: cargo test --workspace

# The vendored sources must actually land in the .crate — that is the
Expand Down
11 changes: 8 additions & 3 deletions rayforce/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//! `(select dict)` and evaluated; `update`/`insert`/`upsert` call the core
//! query builtins directly. Mirrors `rayforce-py/types/table.py`.

use crate::error::{check, materialize, Result};
use crate::error::{check, materialize, RayError, Result};
use crate::expr::Expr;
use crate::ops::Operation;
use crate::runtime::eval_value;
Expand Down Expand Up @@ -304,12 +304,12 @@ impl Table {

/// First `n` rows.
pub fn head(&self, n: i64) -> Result<Table> {
Table::from_value(take_rows(self.as_value(), n)?)
Table::from_value(take_rows(self.as_value(), take_magnitude(n, "head")?)?)
}

/// Last `n` rows.
pub fn tail(&self, n: i64) -> Result<Table> {
Table::from_value(take_rows(self.as_value(), -n)?)
Table::from_value(take_rows(self.as_value(), -take_magnitude(n, "tail")?)?)
}

/// Take `n` rows (negative counts from the end).
Expand Down Expand Up @@ -349,3 +349,8 @@ fn take_rows(table: &Value, n: i64) -> Result<Value> {
let ast = Value::list(&[Value::name_ref("take"), table.clone(), Value::i64(n)]);
eval_value(&ast)
}

fn take_magnitude(n: i64, op: &str) -> Result<i64> {
n.checked_abs()
.ok_or_else(|| RayError::binding(format!("{op}: count magnitude overflows i64")))
}
3 changes: 3 additions & 0 deletions rayforce/src/vector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,9 @@ impl Value {
}
unsafe {
let n = self.len();
if n == 0 {
return Ok(&[]);
}
let ptr = raw::data(self.as_ptr()) as *const T;
Ok(std::slice::from_raw_parts(ptr, n))
}
Expand Down
5 changes: 3 additions & 2 deletions rayforce/tests/containers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,9 @@ fn bool_and_temporal_slices() {
assert_eq!(b.bool_slice().unwrap(), &[1u8, 0, 1]);

let dates = Value::empty_vec(rayforce::sys::RAY_DATE as i8, 0);
let _ = dates; // construct-by-slice for temporals comes via Value::vec on i32 raw later
// date/time/timestamp readers reject a plain i64 vector
assert_eq!(dates.date_days_slice().unwrap(), &[]);
// construct-by-slice for temporals comes via Value::vec on i32 raw later
// date/time/timestamp readers reject a plain i64 vector
let v = Value::vec(&[1i64, 2, 3]);
assert!(v.date_days_slice().is_err());
assert!(v.timestamp_nanos_slice().is_err());
Expand Down
32 changes: 32 additions & 0 deletions rayforce/tests/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,38 @@ fn head_tail_take() {
tl.column("size").unwrap().get(0).unwrap().as_i64().unwrap(),
50
);
let h_neg = t.head(-2).unwrap();
assert_eq!(
h_neg
.column("size")
.unwrap()
.as_slice::<i64>()
.unwrap()
.to_vec(),
vec![10, 20]
);
let tl_neg = t.tail(-2).unwrap();
assert_eq!(
tl_neg
.column("size")
.unwrap()
.as_slice::<i64>()
.unwrap()
.to_vec(),
vec![40, 50]
);
let take_neg = t.take(-2).unwrap();
assert_eq!(
take_neg
.column("size")
.unwrap()
.as_slice::<i64>()
.unwrap()
.to_vec(),
vec![40, 50]
);
assert!(t.head(i64::MIN).is_err());
assert!(t.tail(i64::MIN).is_err());
Ok(())
})
.unwrap();
Expand Down