| Crates.io | legalis-sg |
| lib.rs | legalis-sg |
| version | 0.1.3 |
| created_at | 2026-01-10 14:25:32.289915+00 |
| updated_at | 2026-01-21 04:32:07.307598+00 |
| description | Singapore jurisdiction support for Legalis-RS (Companies Act, Employment Act, PDPA, Consumer Protection) |
| homepage | https://github.com/cool-japan/legalis |
| repository | https://github.com/cool-japan/legalis |
| max_upload_size | |
| id | 2034267 |
| size | 776,444 |
Comprehensive modeling of Singapore law for the Legalis-RS legal framework.
This crate provides type-safe representations and validation logic for seven major legal domains in Singapore:
Add to your Cargo.toml:
[dependencies]
legalis-sg = "0.1.3"
use legalis_sg::companies::*;
// Create a Singapore Pte Ltd company
let company = Company::builder()
.name("Tech Innovations Pte Ltd")
.company_type(CompanyType::PrivateLimited)
.share_capital(ShareCapital::new(100_000_00)) // SGD 100,000
.add_director(Director::new("John Tan", "S1234567A", true)) // Resident
.registered_address(Address::singapore("1 Raffles Place", "048616"))
.build()?;
// Validate
match validate_company_formation(&company) {
Ok(report) => println!("✅ Company formation valid"),
Err(CompaniesError::NoResidentDirector) => {
eprintln!("❌ No resident director (s. 145 violation)");
}
Err(e) => eprintln!("❌ {}", e),
}
use legalis_sg::employment::*;
// Calculate CPF for 30-year-old earning SGD 5,000/month
let cpf = CpfContribution::new(30, 5_000_00);
let breakdown = cpf.calculate()?;
println!("Employer: SGD {:.2} (17%)", breakdown.employer_amount_sgd());
println!("Employee: SGD {:.2} (20%)", breakdown.employee_amount_sgd());
// Output: Employer: SGD 850.00, Employee: SGD 1,000.00
use legalis_sg::pdpa::*;
// Record marketing consent
let consent = ConsentRecord::builder()
.data_subject_id("customer@example.com")
.purpose(PurposeOfCollection::Marketing)
.consent_method(ConsentMethod::Electronic)
.add_data_category(PersonalDataCategory::Email)
.timestamp_now()
.build()?;
validate_consent(&consent)?;
use legalis_sg::consumer::*;
let contract = ConsumerContract::new()
.business_name("Electronics Store")
.consumer_name("Jane Lim")
.add_term("No refunds under any circumstances");
let practices = detect_unfair_practices(&contract);
for practice in practices {
println!("⚠️ {:?}: {}", practice.practice_type, practice.description);
}
use legalis_sg::banking::*;
use chrono::Utc;
// Create capital adequacy data
let capital = CapitalAdequacy {
cet1_capital_sgd: 1_500_000_000_00, // SGD 15M
at1_capital_sgd: 300_000_000_00, // SGD 3M
tier2_capital_sgd: 500_000_000_00, // SGD 5M
risk_weighted_assets_sgd: 10_000_000_000_00, // SGD 100M
calculation_date: Utc::now(),
};
// CET1: 15M / 100M = 15.0% (> 6.5% ✓)
// Tier 1: 18M / 100M = 18.0% (> 8.0% ✓)
// Total: 23M / 100M = 23.0% (> 10.0% ✓)
assert!(capital.meets_regulatory_minimum());
let bank = Bank::new(
"197700001E".to_string(),
"Singapore Commercial Bank Ltd".to_string(),
BankLicenseType::FullBank,
Utc::now(),
true,
"Singapore".to_string(),
capital,
);
let report = validate_bank(&bank)?;
println!("CET1: {:.2}%", report.capital_status.cet1_ratio);
use legalis_sg::payment::*;
use chrono::Utc;
// Create a cryptocurrency exchange
let provider = PaymentServiceProviderBuilder::new()
.uen("202098765B".to_string())
.name("Singapore Crypto Exchange Pte Ltd".to_string())
.license_type(PaymentLicenseType::MajorPaymentInstitution)
.license_date(Utc::now())
.add_service(PaymentServiceType::DigitalPaymentToken)
.add_dpt_service(DptServiceType::Exchange)
.add_dpt_service(DptServiceType::Custody)
.monthly_volume_sgd(500_000_000) // SGD 5M/month
.has_aml_officer(true)
.build()?;
let report = validate_payment_provider(&provider)?;
if report.is_compliant {
println!("✅ DPT service provider compliant");
}
legalis-sg/
├── src/
│ ├── lib.rs # Public API, module exports
│ ├── citation.rs # Singapore legal citation system
│ ├── companies/ # Companies Act (Cap. 50)
│ │ ├── mod.rs
│ │ ├── types.rs # Company, Director, ShareCapital
│ │ ├── validator.rs # Formation, compliance validation
│ │ ├── error.rs # CompaniesError enum
│ │ ├── acra.rs # ACRA-specific logic
│ │ └── governance.rs # AGM, annual returns
│ ├── employment/ # Employment Act (Cap. 91)
│ │ ├── mod.rs
│ │ ├── types.rs # EmploymentContract, CpfContribution
│ │ ├── validator.rs # Contract, CPF, leave validation
│ │ ├── error.rs # EmploymentError enum
│ │ ├── cpf.rs # CPF calculations
│ │ ├── leave.rs # Leave entitlement logic
│ │ └── termination.rs # Notice period calculations
│ ├── pdpa/ # Personal Data Protection Act 2012
│ │ ├── mod.rs
│ │ ├── types.rs # ConsentRecord, DataBreachNotification
│ │ ├── validator.rs # Consent, breach validation
│ │ ├── error.rs # PdpaError enum
│ │ ├── consent.rs # Consent management
│ │ ├── breach.rs # Breach notification workflow
│ │ ├── dnc.rs # DNC Registry logic
│ │ └── dpo.rs # DPO requirement assessment
│ ├── consumer/ # Consumer Protection
│ │ ├── mod.rs
│ │ ├── types.rs # ConsumerContract, UnfairPractice
│ │ ├── validator.rs # Practice detection
│ │ ├── error.rs # ConsumerError enum
│ │ ├── sale_of_goods.rs # Implied terms
│ │ └── unfair_practices.rs # Detection algorithms
│ ├── ip/ # Intellectual Property
│ │ ├── mod.rs
│ │ ├── types.rs # Patent, Trademark, Copyright, Design
│ │ ├── validator.rs # IP validation, similarity, fair dealing
│ │ └── error.rs # IpError enum
│ ├── banking/ # Banking Act (Cap. 19)
│ │ ├── mod.rs
│ │ ├── types.rs # Bank, CapitalAdequacy, AML types
│ │ ├── validator.rs # Basel III, license, AML validation
│ │ └── error.rs # BankingError enum
│ └── payment/ # Payment Services Act 2019
│ ├── mod.rs
│ ├── types.rs # PaymentServiceProvider, DPT, Safeguarding
│ ├── validator.rs # License, safeguarding, DPT validation
│ └── error.rs # PaymentError enum
├── examples/ # 10 comprehensive examples
│ ├── acra_company_registration.rs
│ ├── employment_contract_validation.rs
│ ├── cpf_contribution_calculator.rs
│ ├── banking_capital_adequacy.rs
│ └── ...
└── tests/ # Integration tests
├── companies_validation_tests.rs
├── employment_cpf_tests.rs
├── pdpa_consent_tests.rs
└── ...
Run any of the 10 comprehensive examples:
# Companies Act
cargo run --example acra_company_registration
# Employment Act
cargo run --example employment_contract_validation
cargo run --example cpf_contribution_calculator
cargo run --example leave_entitlement_calculator
cargo run --example termination_notice_checker
# Consumer Protection
cargo run --example consumer_contract_analysis
cargo run --example sale_of_goods_validation
# Intellectual Property
cargo run --example ip_comprehensive_validation
# Banking Act
cargo run --example banking_capital_adequacy
# Payment Services Act
cargo run --example payment_services_dpt
# Run all tests
cargo nextest run --package legalis-sg
# Run specific domain tests
cargo test --package legalis-sg --test companies_validation_tests
cargo test --package legalis-sg --test employment_contract_tests
cargo test --package legalis-sg --test pdpa_consent_tests
cargo test --package legalis-sg --test consumer_protection_tests
# Run with coverage
cargo nextest run --package legalis-sg --all-features
All business entities are assigned a 9-10 digit UEN by ACRA for identification.
Mandatory retirement savings for citizens/PRs:
Do Not Call Registry allows opt-out of marketing communications:
Electronic filing system for:
In accordance with Singapore's multilingual context, error messages are provided in:
ExcessiveWorkingHours { actual: 50.0, limit: 44.0 }
Displays as:
Working hours 50h/week exceeds limit 44h/week (Employment Act s. 38)
工作时间每周50小时超过法定限制每周44小时 (雇佣法第38条)
Waktu bekerja 50j/minggu melebihi had 44j/minggu (Akta Pekerjaan s. 38)
Note: While Singapore has four official languages (English, Chinese, Malay, Tamil), the trilingual pattern (English/Chinese/Malay) covers the primary languages used in business and legal contexts. Tamil support can be added optionally. A production deployment would require verification by native speakers and legal professionals familiar with terminology in each language.
Key differences between Singapore PDPA and EU GDPR:
| Feature | GDPR | PDPA |
|---|---|---|
| Scope | EU/EEA + extraterritorial | Singapore organizations |
| Legal Basis | 6 lawful bases | Consent-centric |
| DPO | Mandatory (certain cases) | Recommended only |
| Breach Notification | 72 hours | 3 calendar days |
| Max Fine | €20M or 4% revenue | SGD 1M |
| Right to Erasure | Yes (Art. 17) | Limited |
| Marketing Opt-Out | GDPR opt-in | DNC Registry |
CompanyType, LeaveType)#[error("Working hours {actual}h exceeds limit {limit}h (EA s. 38)\n工作时间 {actual}小时超过限制 {limit}小时 (雇佣法第38条)")]
ExcessiveWorkingHours { actual: f64, limit: f64 }
All errors and documentation include legal citations:
Complex types use builders for ergonomic construction:
let company = Company::builder()
.name("Acme Pte Ltd")
.company_type(CompanyType::PrivateLimited)
.share_capital(ShareCapital::new(100_000_00))
.build()?;
Multi-stage validation:
legalis-core - Core legal framework typeslegalis-i18n - Internationalization supportchrono - Date/time handlingserde - Serialization/deserializationthiserror - Error handlinguuid - Unique identifiersFuture enhancements:
Contributions welcome! Please ensure:
cargo nextest run --no-run)cargo clippy -- -D warnings)cargo nextest run)cargo fmt)Licensed under either of:
at your option.