1#[macro_use]
2mod macros;
3
4use core::any;
5use core::cmp::Ordering;
6use core::fmt;
7
8#[cfg(feature = "musli")]
9use musli::{Decode, Encode};
10#[cfg(feature = "serde")]
11use serde::{Deserialize, Serialize};
12
13use crate::alloc;
14use crate::alloc::prelude::*;
15use crate::runtime;
16use crate::{self as rune};
17use crate::{declare_dyn_trait, hash_in, Hash, TypeHash};
18
19use super::{
20 AnyTypeInfo, Bytes, ExpectedType, FromValue, Inline, Object, OwnedTuple, Repr, RuntimeError,
21 ToValue, Tuple, Type, TypeInfo, Value, VmErrorKind, VmIntegerRepr,
22};
23
24pub use rune_macros::ToConstValue;
96
97pub trait IntoConstValue {
99 #[doc(hidden)]
101 fn into_const_value(self) -> alloc::Result<ConstValue>;
102}
103
104impl IntoConstValue for ConstValue {
105 #[inline]
106 fn into_const_value(self) -> alloc::Result<ConstValue> {
107 Ok(self)
108 }
109}
110
111impl IntoConstValue for &ConstValue {
112 #[inline]
113 fn into_const_value(self) -> alloc::Result<ConstValue> {
114 self.try_clone()
115 }
116}
117
118pub fn from_const_value<T>(value: impl IntoConstValue) -> Result<T, RuntimeError>
131where
132 T: FromConstValue,
133{
134 T::from_const_value(value.into_const_value()?)
135}
136
137pub fn to_const_value(value: impl ToConstValue) -> Result<ConstValue, RuntimeError> {
150 value.to_const_value()
151}
152
153pub trait ToConstValue: Sized {
155 fn to_const_value(self) -> Result<ConstValue, RuntimeError>;
157
158 #[inline]
160 #[doc(hidden)]
161 fn construct() -> alloc::Result<Option<ConstConstructImpl>> {
162 Ok(None)
163 }
164}
165
166impl ToConstValue for ConstValue {
167 #[inline]
168 fn to_const_value(self) -> Result<ConstValue, RuntimeError> {
169 Ok(self)
170 }
171}
172
173impl ToConstValue for Value {
174 #[inline]
175 fn to_const_value(self) -> Result<ConstValue, RuntimeError> {
176 ConstValue::from_value_ref(&self)
177 }
178}
179
180#[derive(Debug, TryClone)]
182#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
183#[cfg_attr(feature = "musli", derive(Decode, Encode))]
184pub(crate) struct ConstInstance {
185 #[try_clone(copy)]
189 pub(crate) hash: Hash,
190 #[try_clone(copy)]
194 pub(crate) variant_hash: Hash,
195 pub(crate) fields: Box<[ConstValue]>,
197}
198
199impl ConstInstance {
200 fn type_info(&self) -> TypeInfo {
201 fn struct_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
202 write!(f, "unknown constant struct")
203 }
204
205 fn variant_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
206 write!(f, "unknown constant variant")
207 }
208
209 match self.hash {
210 Option::<Value>::HASH => TypeInfo::any::<Option<Value>>(),
211 runtime::Vec::HASH => TypeInfo::any::<runtime::Vec>(),
212 OwnedTuple::HASH => TypeInfo::any::<OwnedTuple>(),
213 Object::HASH => TypeInfo::any::<Object>(),
214 hash if self.variant_hash == Hash::EMPTY => {
215 TypeInfo::any_type_info(AnyTypeInfo::new(struct_name, hash))
216 }
217 hash => TypeInfo::any_type_info(AnyTypeInfo::new(variant_name, hash)),
218 }
219 }
220}
221
222#[derive(Debug, TryClone)]
223#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
224#[cfg_attr(feature = "musli", derive(Decode, Encode))]
225pub(crate) enum ConstValueKind {
226 Inline(#[try_clone(copy)] Inline),
228 String(Box<str>),
230 Bytes(Box<[u8]>),
232 Instance(Box<ConstInstance>),
234}
235
236impl ConstValueKind {
237 #[inline]
238 fn type_info(&self) -> TypeInfo {
239 match self {
240 ConstValueKind::Inline(value) => value.type_info(),
241 ConstValueKind::String(..) => TypeInfo::any::<String>(),
242 ConstValueKind::Bytes(..) => TypeInfo::any::<Bytes>(),
243 ConstValueKind::Instance(instance) => instance.type_info(),
244 }
245 }
246}
247
248#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(transparent))]
250#[cfg_attr(feature = "musli", derive(Encode, Decode), musli(transparent))]
251pub struct ConstValue {
252 kind: ConstValueKind,
253}
254
255impl ConstValue {
256 pub fn string(value: impl AsRef<str>) -> Result<ConstValue, RuntimeError> {
258 let value = Box::try_from(value.as_ref())?;
259 Ok(Self::from(ConstValueKind::String(value)))
260 }
261
262 pub fn bytes(value: impl AsRef<[u8]>) -> Result<ConstValue, RuntimeError> {
264 let value = Box::try_from(value.as_ref())?;
265 Ok(Self::from(ConstValueKind::Bytes(value)))
266 }
267
268 pub fn tuple(fields: Box<[ConstValue]>) -> Result<ConstValue, RuntimeError> {
270 let instance = ConstInstance {
271 hash: OwnedTuple::HASH,
272 variant_hash: Hash::EMPTY,
273 fields,
274 };
275
276 let instance = Box::try_new(instance)?;
277 Ok(Self::from(ConstValueKind::Instance(instance)))
278 }
279
280 pub fn for_struct<const N: usize>(
282 hash: Hash,
283 fields: [ConstValue; N],
284 ) -> Result<ConstValue, RuntimeError> {
285 let fields = Box::<[ConstValue]>::try_from(fields)?;
286
287 let instance = ConstInstance {
288 hash,
289 variant_hash: Hash::EMPTY,
290 fields,
291 };
292
293 let instance = Box::try_new(instance)?;
294 Ok(Self::from(ConstValueKind::Instance(instance)))
295 }
296
297 pub fn as_integer<T>(&self) -> Result<T, RuntimeError>
310 where
311 T: TryFrom<i64> + TryFrom<u64>,
312 {
313 match self.kind {
314 ConstValueKind::Inline(Inline::Signed(value)) => match value.try_into() {
315 Ok(number) => Ok(number),
316 Err(..) => Err(RuntimeError::new(
317 VmErrorKind::ValueToIntegerCoercionError {
318 from: VmIntegerRepr::from(value),
319 to: any::type_name::<T>(),
320 },
321 )),
322 },
323 ConstValueKind::Inline(Inline::Unsigned(value)) => match value.try_into() {
324 Ok(number) => Ok(number),
325 Err(..) => Err(RuntimeError::new(
326 VmErrorKind::ValueToIntegerCoercionError {
327 from: VmIntegerRepr::from(value),
328 to: any::type_name::<T>(),
329 },
330 )),
331 },
332 ref kind => Err(RuntimeError::new(VmErrorKind::ExpectedNumber {
333 actual: kind.type_info(),
334 })),
335 }
336 }
337
338 inline_macros!(inline_into);
339
340 #[inline]
342 pub fn into_tuple(self) -> Result<Box<[ConstValue]>, ExpectedType> {
343 match self.kind {
344 ConstValueKind::Instance(instance) => {
345 let instance = Box::into_inner(instance);
346
347 match instance.hash {
348 OwnedTuple::HASH => Ok(instance.fields),
349 _ => Err(ExpectedType::new::<Tuple>(instance.type_info())),
350 }
351 }
352 kind => Err(ExpectedType::new::<Tuple>(kind.type_info())),
353 }
354 }
355
356 pub(crate) fn as_kind(&self) -> &ConstValueKind {
358 &self.kind
359 }
360
361 pub(crate) fn from_value_ref(value: &Value) -> Result<ConstValue, RuntimeError> {
363 let kind = match value.as_ref() {
364 Repr::Inline(value) => ConstValueKind::Inline(*value),
365 Repr::Dynamic(value) => {
366 return Err(RuntimeError::from(VmErrorKind::ConstNotSupported {
367 actual: value.type_info(),
368 }));
369 }
370 Repr::Any(value) => match value.type_hash() {
371 String::HASH => {
372 return ConstValue::string(value.borrow_ref::<String>()?.as_str());
373 }
374 Bytes::HASH => {
375 return ConstValue::bytes(value.borrow_ref::<Bytes>()?.as_slice());
376 }
377 runtime::OwnedTuple::HASH => {
378 let tuple = value.borrow_ref::<runtime::OwnedTuple>()?;
379 let mut const_tuple = Vec::try_with_capacity(tuple.len())?;
380
381 for value in tuple.iter() {
382 const_tuple.try_push(Self::from_value_ref(value)?)?;
383 }
384
385 return ConstValue::tuple(const_tuple.try_into_boxed_slice()?);
386 }
387 Object::HASH => {
388 let object = value.borrow_ref::<Object>()?;
389 let mut fields = Vec::try_with_capacity(object.len())?;
390
391 for (key, value) in object.iter() {
392 let key = ConstValue::string(key.as_str())?;
393 let value = Self::from_value_ref(value)?;
394 fields.try_push(ConstValue::tuple(Box::try_from([key, value])?)?)?;
395 }
396
397 let instance = ConstInstance {
398 hash: Object::HASH,
399 variant_hash: Hash::EMPTY,
400 fields: fields.try_into_boxed_slice()?,
401 };
402
403 let instance = Box::try_new(instance)?;
404 ConstValueKind::Instance(instance)
405 }
406 Option::<Value>::HASH => {
407 let option = value.borrow_ref::<Option<Value>>()?;
408
409 let (variant_hash, fields) = match &*option {
410 Some(some) => (
411 hash_in!(crate, ::std::option::Option::Some),
412 Box::try_from([Self::from_value_ref(some)?])?,
413 ),
414 None => (hash_in!(crate, ::std::option::Option::None), Box::default()),
415 };
416
417 let instance = ConstInstance {
418 hash: Option::<Value>::HASH,
419 variant_hash,
420 fields,
421 };
422 ConstValueKind::Instance(Box::try_new(instance)?)
423 }
424 runtime::Vec::HASH => {
425 let vec = value.borrow_ref::<runtime::Vec>()?;
426 let mut const_vec = Vec::try_with_capacity(vec.len())?;
427
428 for value in vec.iter() {
429 const_vec.try_push(Self::from_value_ref(value)?)?;
430 }
431
432 let fields = Box::try_from(const_vec)?;
433
434 let instance = ConstInstance {
435 hash: runtime::Vec::HASH,
436 variant_hash: Hash::EMPTY,
437 fields,
438 };
439 ConstValueKind::Instance(Box::try_new(instance)?)
440 }
441 _ => {
442 return Err(RuntimeError::from(VmErrorKind::ConstNotSupported {
443 actual: value.type_info(),
444 }));
445 }
446 },
447 };
448
449 Ok(Self { kind })
450 }
451
452 #[inline]
453 #[cfg(test)]
454 pub(crate) fn to_value(&self) -> Result<Value, RuntimeError> {
455 self.to_value_with(&EmptyConstContext)
456 }
457
458 pub(crate) fn as_string(&self) -> Result<&str, ExpectedType> {
460 let ConstValueKind::String(value) = &self.kind else {
461 return Err(ExpectedType::new::<String>(self.kind.type_info()));
462 };
463
464 Ok(value)
465 }
466
467 pub(crate) fn as_pair(&self) -> Result<(&ConstValue, &ConstValue), ExpectedType> {
469 let ConstValueKind::Instance(instance) = &self.kind else {
470 return Err(ExpectedType::new::<Tuple>(self.kind.type_info()));
471 };
472
473 if !matches!(instance.hash, OwnedTuple::HASH) {
474 return Err(ExpectedType::new::<Tuple>(instance.type_info()));
475 }
476
477 let [a, b] = instance.fields.as_ref() else {
478 return Err(ExpectedType::new::<Tuple>(instance.type_info()));
479 };
480
481 Ok((a, b))
482 }
483
484 pub(crate) fn to_value_with(&self, cx: &dyn ConstContext) -> Result<Value, RuntimeError> {
490 match &self.kind {
491 ConstValueKind::Inline(value) => Ok(Value::from(*value)),
492 ConstValueKind::String(string) => Ok(Value::try_from(string.as_ref())?),
493 ConstValueKind::Bytes(b) => Ok(Value::try_from(b.as_ref())?),
494 ConstValueKind::Instance(instance) => match &**instance {
495 ConstInstance {
496 hash,
497 variant_hash: Hash::EMPTY,
498 fields,
499 } => match *hash {
500 runtime::OwnedTuple::HASH => {
501 let mut t = Vec::try_with_capacity(fields.len())?;
502
503 for value in fields.iter() {
504 t.try_push(Self::to_value_with(value, cx)?)?;
505 }
506
507 Ok(Value::try_from(OwnedTuple::try_from(t)?)?)
508 }
509 runtime::Vec::HASH => {
510 let mut v = runtime::Vec::with_capacity(fields.len())?;
511
512 for value in fields.iter() {
513 v.push(Self::to_value_with(value, cx)?)?;
514 }
515
516 Ok(Value::try_from(v)?)
517 }
518 runtime::Object::HASH => {
519 let mut o = Object::with_capacity(fields.len())?;
520
521 for value in fields.iter() {
522 let (key, value) = value.as_pair()?;
523 let key = key.as_string()?.try_to_string()?;
524 let value = Self::to_value_with(value, cx)?;
525 o.insert(key, value)?;
526 }
527
528 Ok(Value::try_from(o)?)
529 }
530 _ => {
531 let Some(constructor) = cx.get(*hash) else {
532 return Err(RuntimeError::missing_constant_constructor(*hash));
533 };
534
535 constructor.const_construct(fields)
536 }
537 },
538 ConstInstance {
539 hash,
540 variant_hash,
541 fields,
542 } => {
543 match (*variant_hash, &fields[..]) {
544 (hash_in!(crate, ::std::option::Option::Some), [value]) => {
546 let value = Self::to_value_with(value, cx)?;
547 Ok(Value::try_from(Some(value))?)
548 }
549 (hash_in!(crate, ::std::option::Option::None), []) => {
550 Ok(Value::try_from(None)?)
551 }
552 _ => Err(RuntimeError::missing_constant_constructor(*hash)),
553 }
554 }
555 },
556 }
557 }
558
559 pub(crate) fn type_info(&self) -> TypeInfo {
561 self.kind.type_info()
562 }
563}
564
565impl TryClone for ConstValue {
566 fn try_clone(&self) -> alloc::Result<Self> {
567 Ok(Self {
568 kind: self.kind.try_clone()?,
569 })
570 }
571}
572
573impl FromValue for ConstValue {
574 #[inline]
575 fn from_value(value: Value) -> Result<Self, RuntimeError> {
576 ConstValue::from_value_ref(&value)
577 }
578}
579
580impl ToValue for ConstValue {
581 #[inline]
582 fn to_value(self) -> Result<Value, RuntimeError> {
583 ConstValue::to_value_with(&self, &EmptyConstContext)
584 }
585}
586
587impl From<ConstValueKind> for ConstValue {
588 #[inline]
589 fn from(kind: ConstValueKind) -> Self {
590 Self { kind }
591 }
592}
593
594impl From<Inline> for ConstValue {
595 #[inline]
596 fn from(value: Inline) -> Self {
597 Self::from(ConstValueKind::Inline(value))
598 }
599}
600
601impl TryFrom<String> for ConstValue {
602 type Error = alloc::Error;
603
604 #[inline]
605 fn try_from(value: String) -> Result<Self, Self::Error> {
606 Ok(Self::from(Box::<str>::try_from(value)?))
607 }
608}
609
610impl From<Box<str>> for ConstValue {
611 #[inline]
612 fn from(value: Box<str>) -> Self {
613 Self::from(ConstValueKind::String(value))
614 }
615}
616
617impl TryFrom<Bytes> for ConstValue {
618 type Error = alloc::Error;
619
620 #[inline]
621 fn try_from(value: Bytes) -> Result<Self, Self::Error> {
622 Self::try_from(value.as_slice())
623 }
624}
625
626impl TryFrom<&str> for ConstValue {
627 type Error = alloc::Error;
628
629 #[inline]
630 fn try_from(value: &str) -> Result<Self, Self::Error> {
631 Ok(ConstValue::from(Box::<str>::try_from(value)?))
632 }
633}
634
635impl ToConstValue for &str {
636 #[inline]
637 fn to_const_value(self) -> Result<ConstValue, RuntimeError> {
638 Ok(ConstValue::try_from(self)?)
639 }
640}
641
642impl From<Box<[u8]>> for ConstValue {
643 #[inline]
644 fn from(value: Box<[u8]>) -> Self {
645 Self::from(ConstValueKind::Bytes(value))
646 }
647}
648
649impl TryFrom<&[u8]> for ConstValue {
650 type Error = alloc::Error;
651
652 #[inline]
653 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
654 Ok(Self::from(Box::<[u8]>::try_from(value)?))
655 }
656}
657
658impl ToConstValue for &[u8] {
659 #[inline]
660 fn to_const_value(self) -> Result<ConstValue, RuntimeError> {
661 Ok(ConstValue::try_from(self)?)
662 }
663}
664
665impl fmt::Debug for ConstValue {
666 #[inline]
667 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
668 self.kind.fmt(f)
669 }
670}
671
672pub trait FromConstValue: Sized {
674 fn from_const_value(value: ConstValue) -> Result<Self, RuntimeError>;
676}
677
678impl FromConstValue for ConstValue {
679 #[inline]
680 fn from_const_value(value: ConstValue) -> Result<Self, RuntimeError> {
681 Ok(value)
682 }
683}
684
685impl FromConstValue for bool {
686 #[inline]
687 fn from_const_value(value: ConstValue) -> Result<Self, RuntimeError> {
688 value.as_bool()
689 }
690}
691
692impl FromConstValue for char {
693 #[inline]
694 fn from_const_value(value: ConstValue) -> Result<Self, RuntimeError> {
695 value.as_char()
696 }
697}
698
699macro_rules! impl_integer {
700 ($($ty:ty),* $(,)?) => {
701 $(
702 impl FromConstValue for $ty {
703 #[inline]
704 fn from_const_value(value: ConstValue) -> Result<Self, RuntimeError> {
705 value.as_integer()
706 }
707 }
708 )*
709 };
710}
711
712impl_integer!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
713
714declare_dyn_trait! {
715 struct ConstConstructVtable;
717
718 pub struct ConstConstructImpl;
720
721 pub trait ConstConstruct {
727 #[doc(hidden)]
729 fn const_construct(&self, fields: &[ConstValue]) -> Result<Value, RuntimeError>;
730
731 #[doc(hidden)]
733 fn runtime_construct(&self, fields: &mut [Value]) -> Result<Value, RuntimeError>;
734 }
735}
736
737pub(crate) trait ConstContext {
738 fn get(&self, hash: Hash) -> Option<&ConstConstructImpl>;
739}
740
741pub(crate) struct EmptyConstContext;
742
743impl ConstContext for EmptyConstContext {
744 #[inline]
745 fn get(&self, _: Hash) -> Option<&ConstConstructImpl> {
746 None
747 }
748}