Skip to content
Draft
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
11 changes: 10 additions & 1 deletion crates/monty/src/heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::{
types::{
Bytes, Dataclass, Dict, DictItemsView, DictKeysView, DictValuesView, FrozenSet, List, LongInt, Module,
MontyIter, NamedTuple, Path, Range, ReMatch, RePattern, Set, Slice, Str, TimeZone, Tuple, allocate_tuple, date,
datetime, timedelta, timezone,
datetime, time, timedelta, timezone,
},
value::Value,
};
Expand Down Expand Up @@ -88,6 +88,7 @@ impl HashState {
| HeapData::LongInt(_)
| HeapData::Date(_)
| HeapData::DateTime(_)
| HeapData::Time(_)
| HeapData::TimeDelta(_)
| HeapData::TimeZone(_) => Self::Unknown,
// Dataclass hashability depends on the mutable flag
Expand Down Expand Up @@ -232,6 +233,7 @@ impl<'a, T: ResourceTracker> HeapReader<'a, T> {
HeapData::ReMatch(re_match) => HeapReadOutput::ReMatch(heap_read(base, re_match, readers)),
HeapData::Date(d) => HeapReadOutput::Date(heap_read(base, d, readers)),
HeapData::DateTime(d) => HeapReadOutput::DateTime(heap_read(base, d, readers)),
HeapData::Time(t) => HeapReadOutput::Time(heap_read(base, t, readers)),
HeapData::TimeDelta(d) => HeapReadOutput::TimeDelta(heap_read(base, d, readers)),
HeapData::TimeZone(d) => HeapReadOutput::TimeZone(heap_read(base, d, readers)),
}
Expand Down Expand Up @@ -317,6 +319,7 @@ pub enum HeapReadOutput<'a> {
ReMatch(HeapRead<'a, ReMatch>),
Date(HeapRead<'a, date::Date>),
DateTime(HeapRead<'a, datetime::DateTime>),
Time(HeapRead<'a, time::Time>),
TimeDelta(HeapRead<'a, timedelta::TimeDelta>),
TimeZone(HeapRead<'a, timezone::TimeZone>),
}
Expand Down Expand Up @@ -1408,6 +1411,12 @@ fn compute_hash_from_read<'h>(
d.get(vm.heap).hash(&mut hasher);
Ok(Some(hasher.finish()))
}
HeapReadOutput::Time(t) => {
let mut hasher = DefaultHasher::new();
heap_disc(vm.heap, id).hash(&mut hasher);
t.get(vm.heap).hash(&mut hasher);
Ok(Some(hasher.finish()))
}
HeapReadOutput::TimeDelta(d) => {
let mut hasher = DefaultHasher::new();
heap_disc(vm.heap, id).hash(&mut hasher);
Expand Down
14 changes: 12 additions & 2 deletions crates/monty/src/heap_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::{
types::{
Bytes, Dataclass, Dict, DictItemsView, DictKeysView, DictValuesView, FrozenSet, List, LongInt, Module,
MontyIter, NamedTuple, Path, PyTrait, Range, ReMatch, RePattern, Set, Slice, Str, Tuple, Type, date, datetime,
dict_view::DictView, timedelta, timezone,
dict_view::DictView, time, timedelta, timezone,
},
value::{EitherStr, Value},
};
Expand Down Expand Up @@ -119,6 +119,8 @@ pub(crate) enum HeapData {
Date(date::Date),
/// A `datetime.datetime` value stored with chrono primitives.
DateTime(datetime::DateTime),
/// A `datetime.time` value stored with narrow integer fields.
Time(time::Time),
/// A `datetime.timedelta` duration value stored with `chrono::TimeDelta`.
TimeDelta(timedelta::TimeDelta),
/// A fixed-offset `datetime.timezone` value.
Expand Down Expand Up @@ -238,6 +240,7 @@ impl HeapData {
Self::ReMatch(_) => Type::ReMatch,
Self::Date(_) => Type::Date,
Self::DateTime(_) => Type::DateTime,
Self::Time(_) => Type::Time,
Self::TimeDelta(_) => Type::TimeDelta,
Self::TimeZone(_) => Type::TimeZone,
}
Expand Down Expand Up @@ -274,6 +277,7 @@ impl HeapData {
Self::ExtFunction(s) => mem::size_of::<String>() + s.len(),
Self::Date(d) => d.py_estimate_size(),
Self::DateTime(d) => d.py_estimate_size(),
Self::Time(t) => t.py_estimate_size(),
Self::TimeDelta(d) => d.py_estimate_size(),
Self::TimeZone(d) => d.py_estimate_size(),
}
Expand Down Expand Up @@ -449,7 +453,7 @@ impl<'h> PyTrait<'h> for HeapReadOutput<'h> {
Self::ReMatch(m) => m.py_bool(vm),
Self::RePattern(p) => p.py_bool(vm),
Self::TimeDelta(td) => td.py_bool(vm),
Self::Date(_) | Self::DateTime(_) | Self::TimeZone(_) => true,
Self::Date(_) | Self::DateTime(_) | Self::Time(_) | Self::TimeZone(_) => true,
}
}

Expand Down Expand Up @@ -479,6 +483,7 @@ impl<'h> PyTrait<'h> for HeapReadOutput<'h> {
HeapReadOutput::TimeDelta(td) => Ok(td.py_call_attr(self_id, vm, attr, args)?),
HeapReadOutput::Date(d) => Ok(d.py_call_attr(self_id, vm, attr, args)?),
HeapReadOutput::DateTime(dt) => Ok(dt.py_call_attr(self_id, vm, attr, args)?),
HeapReadOutput::Time(t) => Ok(t.py_call_attr(self_id, vm, attr, args)?),
// Types without methods — return AttributeError
_ => {
args.drop_with_heap(vm);
Expand Down Expand Up @@ -516,6 +521,7 @@ impl<'h> PyTrait<'h> for HeapReadOutput<'h> {
Self::RePattern(p) => p.py_type(vm),
Self::Date(d) => d.py_type(vm),
Self::DateTime(d) => d.py_type(vm),
Self::Time(t) => t.py_type(vm),
Self::TimeDelta(d) => d.py_type(vm),
Self::TimeZone(d) => d.py_type(vm),
}
Expand Down Expand Up @@ -647,6 +653,7 @@ impl<'h> PyTrait<'h> for HeapReadOutput<'h> {
// Datetime types
(HeapReadOutput::Date(a), HeapReadOutput::Date(b)) => a.py_eq(b, vm),
(HeapReadOutput::DateTime(a), HeapReadOutput::DateTime(b)) => a.py_eq(b, vm),
(HeapReadOutput::Time(a), HeapReadOutput::Time(b)) => a.py_eq(b, vm),
(HeapReadOutput::TimeDelta(a), HeapReadOutput::TimeDelta(b)) => a.py_eq(b, vm),
(HeapReadOutput::TimeZone(a), HeapReadOutput::TimeZone(b)) => a.py_eq(b, vm),
// Identity-only types (handled by HeapId comparison above)
Expand Down Expand Up @@ -713,6 +720,7 @@ impl<'h> PyTrait<'h> for HeapReadOutput<'h> {
Self::ExtFunction(name) => Ok(write!(f, "<function '{}' external>", name.get(vm.heap))?),
Self::Date(d) => d.py_repr_fmt(f, vm, heap_ids),
Self::DateTime(d) => d.py_repr_fmt(f, vm, heap_ids),
Self::Time(t) => t.py_repr_fmt(f, vm, heap_ids),
Self::TimeDelta(d) => d.py_repr_fmt(f, vm, heap_ids),
Self::TimeZone(d) => d.py_repr_fmt(f, vm, heap_ids),
}
Expand All @@ -735,6 +743,7 @@ impl<'h> PyTrait<'h> for HeapReadOutput<'h> {
// Datetime types have their own str output
Self::Date(d) => d.py_str(vm),
Self::DateTime(d) => d.py_str(vm),
Self::Time(t) => t.py_str(vm),
Self::TimeDelta(d) => d.py_str(vm),
Self::TimeZone(d) => d.py_str(vm),
// All other types use repr
Expand Down Expand Up @@ -912,6 +921,7 @@ impl<'h> PyTrait<'h> for HeapReadOutput<'h> {
Self::Path(p) => p.py_getattr(attr, vm),
Self::Date(d) => d.py_getattr(attr, vm),
Self::DateTime(dt) => dt.py_getattr(attr, vm),
Self::Time(t) => t.py_getattr(attr, vm),
Self::TimeDelta(td) => td.py_getattr(attr, vm),
_ => Ok(None),
}
Expand Down
4 changes: 4 additions & 0 deletions crates/monty/src/intern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,8 @@ pub enum StaticStrings {
// datetime module strings
Datetime,
Date,
/// `datetime.time` class name and attribute on `datetime.datetime`.
Time,
Timedelta,
Timezone,
Today,
Expand All @@ -484,6 +486,8 @@ pub enum StaticStrings {
Minute,
Second,
Microsecond,
/// `datetime.time.fold` attribute / `time(fold=...)` keyword.
Fold,
// timedelta constructor/attribute names
Days,
Seconds,
Expand Down
2 changes: 2 additions & 0 deletions crates/monty/src/modules/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//! This module exposes a minimal phase-1 surface:
//! - `date`
//! - `datetime`
//! - `time`
//! - `timedelta`
//! - `timezone`
//!
Expand Down Expand Up @@ -35,6 +36,7 @@ pub fn create_module(vm: &mut VM<'_, '_, impl ResourceTracker>) -> Result<HeapId
Value::Builtin(Builtins::Type(Type::DateTime)),
vm,
);
module.set_attr(StaticStrings::Time, Value::Builtin(Builtins::Type(Type::Time)), vm);
module.set_attr(
StaticStrings::Timedelta,
Value::Builtin(Builtins::Type(Type::TimeDelta)),
Expand Down
5 changes: 5 additions & 0 deletions crates/monty/src/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,11 @@ impl MontyObject {
offset_seconds: tz.offset_seconds,
name: tz.name.clone(),
}),
// Phase 1: `time` has no dedicated `MontyObject` variant yet;
// round-tripping it through the public API falls back to a repr
// placeholder. We can add a `MontyTime` variant in a future phase
// once host bindings need it.
HeapData::Time(_) => repr_or_error(object, vm),
// Cells are internal closure implementation details
HeapData::Cell(cell) => {
// Show the cell's contents
Expand Down
1 change: 1 addition & 0 deletions crates/monty/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub mod re_pattern;
pub mod set;
pub mod slice;
pub mod str;
pub mod time;
pub mod timedelta;
pub mod timezone;
pub mod tuple;
Expand Down
Loading
Loading