use allocative::Allocative;
use derive_more::Display;
use serde::Serialize;
use starlark_derive::starlark_module;
use starlark_derive::starlark_value;
use starlark_derive::NoSerialize;
use starlark_derive::ProvidesStaticType;
use starlark_map::small_map::SmallMap;
use crate as starlark;
use crate::assert::Assert;
use crate::docs::DocItem;
use crate::docs::DocMember;
use crate::docs::DocParam;
use crate::environment::GlobalsBuilder;
use crate::environment::Methods;
use crate::environment::MethodsBuilder;
use crate::environment::MethodsStatic;
use crate::eval::runtime::params::display::PARAM_FMT_OPTIONAL;
use crate::eval::Arguments;
use crate::eval::Evaluator;
use crate::values::list::UnpackList;
use crate::values::none::NoneType;
use crate::values::starlark_value_as_type::StarlarkValueAsType;
use crate::values::tuple::UnpackTuple;
use crate::values::Heap;
use crate::values::StarlarkValue;
use crate::values::StringValue;
use crate::values::Value;
use crate::values::ValueOfUnchecked;
#[derive(
Debug,
derive_more::Display,
Allocative,
NoSerialize,
ProvidesStaticType
)]
#[display("input")]
struct InputTypeRepr;
#[derive(
Debug,
derive_more::Display,
Allocative,
NoSerialize,
ProvidesStaticType
)]
#[display("output")]
struct OutputTypeRepr;
#[starlark_value(type = "input")]
impl<'v> StarlarkValue<'v> for InputTypeRepr {}
#[starlark_value(type = "output")]
impl<'v> StarlarkValue<'v> for OutputTypeRepr {}
#[starlark_module]
#[allow(unused_variables)] fn globals(builder: &mut GlobalsBuilder) {
const Input: StarlarkValueAsType<InputTypeRepr> = StarlarkValueAsType::new();
const Output: StarlarkValueAsType<OutputTypeRepr> = StarlarkValueAsType::new();
fn simple(
arg_int: i32,
arg_bool: bool,
arg_vec: UnpackList<&str>,
arg_dict: SmallMap<String, (bool, i32)>,
) -> anyhow::Result<NoneType> {
unimplemented!()
}
fn default_arg<'v>(
arg1: Option<Value<'v>>,
#[starlark(default = NoneType)] arg2: Value<'v>,
eval: &mut Evaluator<'v, '_, '_>,
) -> anyhow::Result<Vec<String>> {
unimplemented!()
}
fn args_kwargs<'v>(
#[starlark(args)] args: UnpackTuple<Value<'v>>,
#[starlark(kwargs)] kwargs: Value<'v>,
) -> anyhow::Result<NoneType> {
unimplemented!()
}
fn custom_types<'v>(
arg1: StringValue<'v>,
arg2: ValueOfUnchecked<'v, InputTypeRepr>,
heap: &'v Heap,
) -> anyhow::Result<ValueOfUnchecked<'v, OutputTypeRepr>> {
unimplemented!()
}
fn pos_named(arg1: i32, #[starlark(require = named)] arg2: i32) -> anyhow::Result<i32> {
unimplemented!()
}
fn with_arguments(args: &Arguments) -> anyhow::Result<i32> {
unimplemented!()
}
}
#[test]
fn test_rustdoc() {
let got = GlobalsBuilder::new().with(globals).build();
let mut a = Assert::new();
a.globals_add(globals);
let expected = a.pass_module(r#"
def args_kwargs(*args, **kwargs: typing.Any) -> None: pass
def custom_types(arg1: str, arg2: Input) -> Output: pass
def default_arg(arg1 = "_", arg2: typing.Any = None) -> list[str]: pass
def pos_named(arg1: int, *, arg2: int) -> int: pass
def simple(arg_int: int, arg_bool: bool, arg_vec: list[str], arg_dict: dict[str, (bool, int)]) -> None: pass
def with_arguments(*args, **kwargs) -> int: pass
"#);
let expected = expected.documentation().members;
let mut got = got.documentation().members;
got.shift_remove("Input");
got.shift_remove("Output");
assert_eq!(expected.len(), got.len());
for (name, mut expected) in expected {
if &name == "default_arg" {
let DocItem::Member(DocMember::Function(expected)) = &mut expected else {
unreachable!()
};
let DocParam { default_value, .. } = expected.params.doc_params_mut().next().unwrap();
*default_value = Some(PARAM_FMT_OPTIONAL.to_owned());
}
assert_eq!(&expected, got.get(&name).unwrap());
}
}
#[derive(ProvidesStaticType, Debug, Display, Allocative, Serialize)]
#[display("obj")]
struct Obj;
#[starlark_value(type = "obj")]
impl<'v> StarlarkValue<'v> for Obj {
fn get_methods() -> Option<&'static Methods> {
static RES: MethodsStatic = MethodsStatic::new();
RES.methods(object)
}
}
#[starlark_module]
fn object(builder: &mut MethodsBuilder) {
fn func1<'v>(this: Value<'v>, foo: String) -> anyhow::Result<String> {
let _ignore = (this, foo);
Ok("func1".to_owned())
}
}
#[test]
fn inner_object_functions_have_docs() {
let heap = Heap::new();
let obj = heap.alloc_simple(Obj);
let item = obj
.get_attr("func1", &heap)
.unwrap()
.unwrap()
.documentation();
match item {
DocItem::Member(DocMember::Function(item)) => {
assert_eq!(item.docs.unwrap().summary, "Docs for func1");
}
_ => panic!("Expected function: {:#?}", item),
}
}
#[starlark_module]
fn module(builder: &mut GlobalsBuilder) {
const MAGIC: i32 = 42;
fn func1(foo: String) -> anyhow::Result<String> {
let _ignore = foo;
Ok("func1".to_owned())
}
}
#[test]
fn inner_module_functions_have_docs() {
let item = GlobalsBuilder::new()
.with(module)
.build()
.get("func1")
.unwrap()
.documentation();
match item {
DocItem::Member(DocMember::Function(item)) => {
assert_eq!(item.docs.unwrap().summary, "Docs for func1");
}
_ => panic!("Expected function: {:#?}", item),
}
}