1use core::fmt;
4
5#[cfg(feature = "std")]
6use std::path::Path;
7
8use crate as rune;
9use crate::alloc::borrow::Cow;
10use crate::alloc::prelude::*;
11use crate::alloc::{self, Box};
12use crate::ast;
13use crate::ast::{Span, Spanned};
14#[cfg(feature = "doc")]
15use crate::compile::meta;
16use crate::compile::{ItemId, Location, MetaInfo, ModId, Pool, Visibility};
17use crate::module::{DocFunction, ModuleItemCommon};
18use crate::runtime::{Call, FieldMap, Protocol};
19use crate::{Hash, Item, ItemBuf};
20
21#[derive(Debug, TryClone, Clone, Copy)]
23#[try_clone(copy)]
24#[non_exhaustive]
25pub struct MetaRef<'a> {
26 pub context: bool,
28 pub hash: Hash,
30 pub item: &'a Item,
32 pub kind: &'a Kind,
34 pub source: Option<&'a SourceMeta>,
36}
37
38#[derive(Debug, TryClone)]
40#[non_exhaustive]
41pub struct SourceMeta {
42 pub location: Location,
44 #[cfg(feature = "std")]
46 #[cfg_attr(rune_docsrs, doc(cfg(feature = "std")))]
47 pub path: Option<Box<Path>>,
48}
49
50#[derive(Debug, TryClone, Clone, Copy, Spanned)]
52#[try_clone(copy)]
53pub(crate) struct Doc {
54 #[rune(span)]
55 pub(crate) span: Span,
56 pub(crate) doc_string: ast::LitStr,
58}
59
60#[derive(Debug, TryClone)]
62#[non_exhaustive]
63pub(crate) struct Meta {
64 pub(crate) context: bool,
66 pub(crate) hash: Hash,
68 pub(crate) item_meta: ItemMeta,
70 pub(crate) kind: Kind,
72 pub(crate) source: Option<SourceMeta>,
74 pub(crate) parameters: Hash,
76}
77
78impl Meta {
79 pub(crate) fn info(&self, pool: &Pool) -> alloc::Result<MetaInfo> {
81 MetaInfo::new(&self.kind, self.hash, Some(pool.item(self.item_meta.item)))
82 }
83
84 pub(crate) fn as_meta_ref<'a>(&'a self, pool: &'a Pool) -> MetaRef<'a> {
86 MetaRef {
87 context: self.context,
88 hash: self.hash,
89 item: pool.item(self.item_meta.item),
90 kind: &self.kind,
91 source: self.source.as_ref(),
92 }
93 }
94
95 pub(crate) fn type_hash_of(&self) -> Option<Hash> {
101 match &self.kind {
102 Kind::Type { .. } => Some(self.hash),
103 Kind::Struct {
104 enum_hash: Hash::EMPTY,
105 ..
106 } => Some(self.hash),
107 Kind::Struct { .. } => None,
108 Kind::Enum { .. } => Some(self.hash),
109 Kind::Function { .. } => Some(self.hash),
110 Kind::Closure { .. } => Some(self.hash),
111 Kind::AsyncBlock { .. } => Some(self.hash),
112 Kind::Const => None,
113 Kind::Static => None,
114 Kind::ConstFn => None,
115 Kind::Macro => None,
116 Kind::AttributeMacro => None,
117 Kind::Import { .. } => None,
118 Kind::Alias { .. } => None,
119 Kind::Module => None,
120 Kind::Trait => None,
121 }
122 }
123}
124
125#[derive(Debug, TryClone)]
127pub enum Fields {
128 Named(FieldsNamed),
130 Unnamed(usize),
132 Empty,
134}
135
136impl Fields {
137 pub(crate) fn as_tuple(&self) -> Option<usize> {
139 match *self {
140 Fields::Unnamed(count) => Some(count),
141 Fields::Empty => Some(0),
142 _ => None,
143 }
144 }
145}
146
147#[derive(Debug, TryClone)]
149#[non_exhaustive]
150pub enum Kind {
151 Type {
154 parameters: Hash,
156 },
157 Struct {
159 fields: Fields,
161 constructor: Option<Signature>,
163 parameters: Hash,
165 enum_hash: Hash,
169 },
170 Enum {
172 parameters: Hash,
174 },
175 Macro,
177 AttributeMacro,
179 Function {
181 associated: Option<AssociatedKind>,
184 trait_hash: Option<Hash>,
186 signature: Signature,
188 is_test: bool,
190 is_bench: bool,
192 parameters: Hash,
194 #[cfg(feature = "doc")]
196 container: Option<Hash>,
197 #[cfg(feature = "doc")]
199 parameter_types: Vec<Hash>,
200 },
201 Closure {
203 call: Call,
205 do_move: bool,
207 },
208 AsyncBlock {
210 call: Call,
212 do_move: bool,
214 },
215 Const,
217 Static,
219 ConstFn,
221 Import(Import),
223 Alias(Alias),
225 Module,
227 Trait,
229}
230
231impl Kind {
232 #[cfg(all(feature = "doc", any(feature = "languageserver", feature = "cli")))]
234 pub(crate) fn as_signature(&self) -> Option<&Signature> {
235 match self {
236 Kind::Struct { constructor, .. } => constructor.as_ref(),
237 Kind::Function { signature, .. } => Some(signature),
238 _ => None,
239 }
240 }
241
242 pub(crate) fn as_parameters(&self) -> Hash {
244 match self {
245 Kind::Function { parameters, .. } => *parameters,
246 Kind::Type { parameters, .. } => *parameters,
247 Kind::Enum { parameters, .. } => *parameters,
248 Kind::Struct { parameters, .. } => *parameters,
249 _ => Hash::EMPTY,
250 }
251 }
252
253 #[cfg(feature = "doc")]
255 pub(crate) fn associated_container(&self) -> Option<Hash> {
256 match *self {
257 Kind::Struct { enum_hash, .. } if enum_hash != Hash::EMPTY => Some(enum_hash),
258 Kind::Function { container, .. } => container,
259 _ => None,
260 }
261 }
262}
263
264#[derive(Debug, TryClone, Clone, Copy)]
266#[try_clone(copy)]
267#[non_exhaustive]
268pub struct Import {
269 pub(crate) location: Location,
271 pub(crate) target: ItemId,
273 pub(crate) module: ModId,
275}
276
277#[derive(Debug, TryClone)]
279pub struct Alias {
280 pub(crate) to: ItemBuf,
282}
283
284#[derive(Debug, TryClone)]
286#[non_exhaustive]
287pub struct FieldsNamed {
288 pub(crate) fields: Box<[FieldMeta]>,
290}
291
292impl FieldsNamed {
293 pub(crate) fn to_fields(&self) -> alloc::Result<FieldMap<Box<str>, usize>> {
295 let mut fields = crate::runtime::new_field_hash_map_with_capacity(self.fields.len())?;
296
297 for f in self.fields.iter() {
298 fields.try_insert(f.name.try_clone()?, f.position)?;
299 }
300
301 Ok(fields)
302 }
303}
304
305#[derive(Debug, TryClone)]
307pub struct FieldMeta {
308 pub(crate) name: Box<str>,
310 pub(crate) position: usize,
312}
313
314#[derive(Debug, TryClone, Clone, Copy)]
316#[try_clone(copy)]
317#[non_exhaustive]
318pub(crate) struct ItemMeta {
319 pub(crate) location: Location,
321 pub(crate) item: ItemId,
323 pub(crate) visibility: Visibility,
325 pub(crate) module: ModId,
327 pub(crate) impl_item: Option<ItemId>,
329}
330
331impl ItemMeta {
332 pub(crate) fn is_public(&self, pool: &Pool) -> bool {
334 self.visibility.is_public() && pool.module(self.module).is_public(pool)
335 }
336}
337
338#[derive(Debug, TryClone)]
340pub struct Signature {
341 #[cfg(feature = "doc")]
343 pub(crate) is_async: bool,
344 #[cfg(feature = "doc")]
346 pub(crate) arguments: Option<Box<[DocArgument]>>,
347 #[cfg(feature = "doc")]
349 pub(crate) return_type: DocType,
350}
351
352impl Signature {
353 #[cfg_attr(not(feature = "doc"), allow(unused_variables))]
355 pub(crate) fn from_context(
356 doc: &DocFunction,
357 common: &ModuleItemCommon,
358 ) -> alloc::Result<Self> {
359 Ok(Self {
360 #[cfg(feature = "doc")]
361 is_async: doc.is_async,
362 #[cfg(feature = "doc")]
363 arguments: context_to_arguments(
364 doc.args,
365 doc.argument_types.as_ref(),
366 common.docs.args(),
367 )?,
368 #[cfg(feature = "doc")]
369 return_type: doc.return_type.try_clone()?,
370 })
371 }
372}
373
374#[cfg(feature = "doc")]
375fn context_to_arguments(
376 args: Option<usize>,
377 types: &[meta::DocType],
378 names: &[String],
379) -> alloc::Result<Option<Box<[meta::DocArgument]>>> {
380 use core::iter;
381
382 let Some(args) = args else {
383 return Ok(None);
384 };
385
386 let len = args.max(types.len()).max(names.len()).max(names.len());
387 let mut out = Vec::try_with_capacity(len)?;
388
389 let mut types = types.iter();
390
391 let names = names
392 .iter()
393 .map(|name| Some(name.as_str()))
394 .chain(iter::repeat(None));
395
396 for (n, name) in (0..len).zip(names) {
397 let empty;
398
399 let ty = match types.next() {
400 Some(ty) => ty,
401 None => {
402 empty = meta::DocType::empty();
403 &empty
404 }
405 };
406
407 out.try_push(meta::DocArgument {
408 name: match name {
409 Some(name) => meta::DocName::Name(Box::try_from(name)?),
410 None => meta::DocName::Index(n),
411 },
412 base: ty.base,
413 generics: ty.generics.try_clone()?,
414 })?;
415 }
416
417 Ok(Some(Box::try_from(out)?))
418}
419
420#[derive(Debug, TryClone)]
422#[cfg(feature = "doc")]
423pub(crate) enum DocName {
424 Name(Box<str>),
426 Index(#[try_clone(copy)] usize),
428}
429
430#[cfg(feature = "cli")]
431impl DocName {
432 pub(crate) fn is_self(&self) -> bool {
433 match self {
434 DocName::Name(name) => name.as_ref() == "self",
435 DocName::Index(..) => false,
436 }
437 }
438}
439
440#[cfg(feature = "doc")]
441impl fmt::Display for DocName {
442 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
443 match self {
444 DocName::Name(name) => write!(f, "{name}"),
445 DocName::Index(index) if *index == 0 => write!(f, "value"),
446 DocName::Index(index) => write!(f, "value{index}"),
447 }
448 }
449}
450
451#[derive(Debug, TryClone)]
453#[cfg(feature = "doc")]
454pub(crate) struct DocArgument {
455 pub(crate) name: DocName,
457 pub(crate) base: Hash,
459 pub(crate) generics: Box<[DocType]>,
461}
462
463#[derive(Default, Debug, TryClone)]
465pub struct DocType {
466 #[cfg(feature = "doc")]
468 pub(crate) base: Hash,
469 #[cfg(feature = "doc")]
471 pub(crate) generics: Box<[DocType]>,
472}
473
474impl DocType {
475 pub(crate) fn empty() -> Self {
477 Self::new(Hash::EMPTY)
478 }
479
480 #[cfg_attr(not(feature = "doc"), allow(unused_variables))]
482 pub fn with_generics<const N: usize>(
483 base: Hash,
484 generics: [DocType; N],
485 ) -> alloc::Result<Self> {
486 Ok(Self {
487 #[cfg(feature = "doc")]
488 base,
489 #[cfg(feature = "doc")]
490 generics: Box::try_from(generics)?,
491 })
492 }
493
494 #[cfg_attr(not(feature = "doc"), allow(unused_variables))]
496 pub(crate) fn new(base: Hash) -> Self {
497 Self {
498 #[cfg(feature = "doc")]
499 base,
500 #[cfg(feature = "doc")]
501 generics: Box::default(),
502 }
503 }
504}
505
506#[derive(Debug, TryClone, PartialEq, Eq, Hash)]
508#[non_exhaustive]
509pub enum AssociatedKind {
510 Protocol(&'static Protocol),
512 FieldFn(&'static Protocol, Cow<'static, str>),
514 IndexFn(&'static Protocol, usize),
516 Instance(Cow<'static, str>),
518}
519
520impl AssociatedKind {
521 pub(crate) fn hash(&self, instance_type: Hash) -> Hash {
523 match self {
524 Self::Protocol(protocol) => Hash::associated_function(instance_type, protocol.hash),
525 Self::IndexFn(protocol, index) => {
526 Hash::index_function(protocol.hash, instance_type, Hash::index(*index))
527 }
528 Self::FieldFn(protocol, field) => {
529 Hash::field_function(protocol.hash, instance_type, field.as_ref())
530 }
531 Self::Instance(name) => Hash::associated_function(instance_type, name.as_ref()),
532 }
533 }
534}
535
536impl fmt::Display for AssociatedKind {
537 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
538 match self {
539 AssociatedKind::Protocol(protocol) => write!(f, "<{}>", protocol.name),
540 AssociatedKind::FieldFn(protocol, field) => {
541 write!(f, ".{field}<{}>", protocol.name)
542 }
543 AssociatedKind::IndexFn(protocol, index) => {
544 write!(f, ".{index}<{}>", protocol.name)
545 }
546 AssociatedKind::Instance(name) => write!(f, "{name}"),
547 }
548 }
549}