// moonbit-4d-schedule - Core Domain Types
///|
pub(all) struct Date {
year : Int
month : Int
day : Int
} derive(Eq, Compare)
///|
pub(all) struct DateTime {
year : Int
month : Int
day : Int
hour : Int
minute : Int
second : Int
} derive(Eq, Compare)
///|
pub(all) enum DayOfWeek {
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
} derive(Eq)
///|
pub(all) struct TimeShift {
name : String
start_hour : Int
end_hour : Int
} derive(Eq)
///|
pub(all) struct WorkCalendar {
id : String
name : String
working_days : Array[DayOfWeek]
shifts : Array[TimeShift]
holidays : Array[Date]
} derive(Eq)
///|
pub(all) enum DependencyType {
FS // Finish-to-Start
SS // Start-to-Start
FF // Finish-to-Finish
SF // Start-to-Finish
} derive(Eq)
///|
pub(all) enum ConstraintType {
AsSoonAsPossible
AsLateAsPossible
MustStartOn
MustFinishOn
StartNoEarlierThan
FinishNoLaterThan
} derive(Eq)
///|
pub(all) struct ActivityConstraint {
constraint_type : ConstraintType
target_date : Date?
} derive(Eq)
///|
pub(all) enum ActivityStatus {
NotStarted
InProgress
Completed
Delayed
} derive(Eq)
///|
pub(all) struct ActivityPredecessor {
activity_id : String
dep_type : DependencyType
lag_days : Double
} derive(Eq)
///|
pub(all) struct Activity {
id : String
code : String
name : String
duration : Double
optimistic_duration : Double
pessimistic_duration : Double
calendar_id : String
constraint : ActivityConstraint
predecessors : Array[ActivityPredecessor]
element_ids : Array[String]
} derive(Eq)
///|
pub(all) struct BimVector3 {
x : Double
y : Double
z : Double
} derive(Eq)
///|
pub(all) struct SpatialBounds {
min_point : BimVector3
max_point : BimVector3
} derive(Eq)
///|
pub(all) enum BimCategory {
Foundation
Column
Beam
Slab
Wall
Roof
DoorWindow
MEP
Equipment
Finishing
CustomCategory(String)
} derive(Eq)
///|
pub(all) struct BimElement {
guid : String
name : String
category : BimCategory
level : String
zone : String
bounds : SpatialBounds
volume : Double
} derive(Eq)
///|
pub(all) enum ResourceKind {
Labor
Equipment
Material
} derive(Eq)
///|
pub(all) struct Resource {
id : String
code : String
name : String
kind : ResourceKind
unit : String
max_capacity : Double
cost_per_unit : Double
} derive(Eq)
///|
pub(all) struct ResourceDemand {
activity_id : String
resource_id : String
units_per_day : Double
} derive(Eq)
///|
pub(all) struct FloatInfo {
early_start : Double
early_finish : Double
late_start : Double
late_finish : Double
total_float : Double
free_float : Double
is_critical : Bool
drag : Double
} derive(Eq)
///|
pub(all) struct ElementState {
guid : String
activity_id : String
status : ActivityStatus
completion_ratio : Double
planned_start : Double
planned_finish : Double
actual_start : Double?
actual_finish : Double?
hex_color : String
} derive(Eq)
///|
pub(all) struct StateSnapshot {
timestamp : Double
date_str : String
elements : Array[ElementState]
overall_completion : Double
active_activity_count : Int
delayed_activity_count : Int
} derive(Eq)
///|
pub(all) struct ScheduleProject {
id : String
name : String
start_date : Date
calendars : Array[WorkCalendar]
activities : Array[Activity]
elements : Array[BimElement]
resources : Array[Resource]
demands : Array[ResourceDemand]
} derive(Eq)
// --- Utility Constructor & Methods ---
///|
pub fn Date::new(year : Int, month : Int, day : Int) -> Date {
{ year, month, day }
}
///|
pub fn Date::to_iso_string(self : Date) -> String {
let m = if self.month < 10 {
"0" + self.month.to_string()
} else {
self.month.to_string()
}
let d = if self.day < 10 {
"0" + self.day.to_string()
} else {
self.day.to_string()
}
self.year.to_string() + "-" + m + "-" + d
}
///|
pub fn Date::is_leap_year(year : Int) -> Bool {
(year % 4 == 0 && year % 100 != 0) || year % 400 == 0
}
///|
pub fn Date::days_in_month(year : Int, month : Int) -> Int {
match month {
1 | 3 | 5 | 7 | 8 | 10 | 12 => 31
4 | 6 | 9 | 11 => 30
2 => if Date::is_leap_year(year) { 29 } else { 28 }
_ => 30
}
}
///|
pub fn Date::add_days(self : Date, days : Int) -> Date {
let mut y = self.year
let mut m = self.month
let mut d = self.day
let mut remaining = days
while remaining > 0 {
d = d + 1
if d > Date::days_in_month(y, m) {
d = 1
m = m + 1
if m > 12 {
m = 1
y = y + 1
}
}
remaining = remaining - 1
}
while remaining < 0 {
d = d - 1
if d < 1 {
m = m - 1
if m < 1 {
m = 12
y = y - 1
}
d = Date::days_in_month(y, m)
}
remaining = remaining + 1
}
{ year: y, month: m, day: d }
}
///|
pub fn Date::day_of_week(self : Date) -> DayOfWeek {
// Zeller's Congruence algorithm
let mut m = self.month
let mut y = self.year
if m < 3 {
m = m + 12
y = y - 1
}
let k = y % 100
let j = y / 100
let h = (self.day + 13 * (m + 1) / 5 + k + k / 4 + j / 4 + 5 * j) % 7
match h {
0 => DayOfWeek::Saturday
1 => DayOfWeek::Sunday
2 => DayOfWeek::Monday
3 => DayOfWeek::Tuesday
4 => DayOfWeek::Wednesday
5 => DayOfWeek::Thursday
_ => DayOfWeek::Friday
}
}
///|
pub fn WorkCalendar::default_standard() -> WorkCalendar {
{
id: "CAL_STD",
name: "Standard 5-Day Work Week",
working_days: [
DayOfWeek::Monday,
DayOfWeek::Tuesday,
DayOfWeek::Wednesday,
DayOfWeek::Thursday,
DayOfWeek::Friday,
],
shifts: [{ name: "Standard Shift", start_hour: 8, end_hour: 17 }],
holidays: [],
}
}
///|
pub fn WorkCalendar::default_seven_day() -> WorkCalendar {
{
id: "CAL_7D",
name: "Continuous 7-Day Work Week",
working_days: [
DayOfWeek::Monday,
DayOfWeek::Tuesday,
DayOfWeek::Wednesday,
DayOfWeek::Thursday,
DayOfWeek::Friday,
DayOfWeek::Saturday,
DayOfWeek::Sunday,
],
shifts: [{ name: "Full Shift", start_hour: 8, end_hour: 18 }],
holidays: [],
}
}
///|
pub fn WorkCalendar::is_working_day(self : WorkCalendar, date : Date) -> Bool {
let dow = date.day_of_week()
let mut is_work_dow = false
for d in self.working_days {
if d == dow {
is_work_dow = true
break
}
}
if !is_work_dow {
return false
}
for h in self.holidays {
if h.year == date.year && h.month == date.month && h.day == date.day {
return false
}
}
true
}
///|
pub fn BimCategory::to_string(self : BimCategory) -> String {
match self {
Foundation => "Foundation"
Column => "Column"
Beam => "Beam"
Slab => "Slab"
Wall => "Wall"
Roof => "Roof"
DoorWindow => "DoorWindow"
MEP => "MEP"
Equipment => "Equipment"
Finishing => "Finishing"
CustomCategory(s) => s
}
}
///|
pub fn BimCategory::default_color(self : BimCategory) -> String {
match self {
Foundation => "#8B4513"
Column => "#708090"
Beam => "#A9A9A9"
Slab => "#D3D3D3"
Wall => "#BC8F8F"
Roof => "#B22222"
DoorWindow => "#87CEEB"
MEP => "#FF8C00"
Equipment => "#9370DB"
Finishing => "#E6E6FA"
CustomCategory(_) => "#4682B4"
}
}
///|
pub fn ActivityStatus::to_color(self : ActivityStatus) -> String {
match self {
NotStarted => "#9CA3AF"
InProgress => "#3B82F6"
Completed => "#10B981"
Delayed => "#EF4444"
}
}