tf-bindgen 0.1.0

Automatically generates Rust bindings for Terraform providers.
Documentation
# Constructs

Having a way to modularize our deployment code can decrease code complexity and reduce code duplication. `tf-bindgen` will utilize constructs similar to [Terraform CDK Constructs](https://developer.hashicorp.com/terraform/cdktf/concepts/constructs) and will use the `Construct` derive macro to implement the required traits.

In this section, we will create a construct to deploy a nginx pod to Kubernetes. To create our construct, we will start with creating a struct and adding the `Construct` derive macro:

```rust
use tf_bindgen::codegen::Construct;
use tf_bindgen::Scope;

#[derive(Construct)]
pub struct Nginx {
	#[construct(id)]
	name: String,
	#[construct(scope)]
	scope: Rc<dyn Scope>
}
```

In addition, we added two fields to our struct: `name` and `scope`. Both fields are necessary and we have to add the `#[construct(id)]` and `#[construct(scope)]` annotation to these fields.

Using this declaration, our derive macro will do nothing more than implementing the `Scope` trait for our `Nginx` struct. This trait is necessary to use this struct instead of stack in resources and data sources. <!-- TODO: link to Scope section -->

## Generating a Builder

In most cases, it will be necessary to pass extra information to our construct. So we need a way to add and set parameters to our construct. We can use the `builder` option of the `Construct` derive macro by adding `#[construct(builder)]` annotation to our struct. In addition, we will add to fields `namespace` and `image` to our struct:

```rust
use tf_bindgen::codegen::{Construct, resource};
use tf_bindgen::Scope;

#[derive(Construct)]
#[construct(builder)]
pub struct Nginx {
	#[construct(id)]
	name: String,
	#[construct(scope)]
	scope: Rc<dyn Scope>,
	#[construct(setter(into_value))]
	namespace: Value<String>,
	#[construct(setter(into_value))]
	image: Value<String>,
}
```

This code snippet allows creating an Nginx construct using the following builder:

```rust
Nginx::create(scope, "<name>")
	.namespace("default")
	.image("nginx")
	.build();
```

Note that we have to implement the build function ourselves. But before we will implement this function, we must consider different setter options:

- `#[construct(setter)]` or no annotation: You can this to generate setters taking the same type as the field as input.
- `#[construct(setter(into))]` This annotation is used to generate setters taking `Into<T>` where T is the type of the field as an argument.
- `#[construct(setter(into_value))]` This annotation is used to generate setters taking `IntoValue<T>` where T is the type of the field as an argument. In addition, this field must be of type `Value<T>`.
- `#[construct(setter(into_value_list))]` This annotation is used to generate setters taking objects implementing `IntoValueList<T>` as an argument. In addition, this field must be of type `Vec<Value<T>>`.
- `#[construct(setter(into_value_set))]` This annotation is used to generate setters taking objects implementing `IntoValueSet<T>` as an argument. In addition, this field must be of type `HashSet<Value<T>>`.
- `#[construct(setter(into_value_map)))]` This annotation is used to generate setters taking objects implementing `IntoValueMap<T>` as an argument. In addition, this field must be of type `HashMap<String, Value<T>>`.

In general, it is recommended to use `Value` wrapped types to ensure better compatibility with `tf-bindgen`. It also allows using references as a Value. <!-- TODO: Link to section about values -->

## Creating Resources

Finally, we want to create our resources. We will create the already mentioned `build` function for that. It is important to note, that we will not implement the function for `Nginx` but rather for `NginxBuilder`, a type generated by our `Construct` derive macro.

To implement our build function, we will start with creating our construct type. For that we will need to clone our `name` and `scope` field. Because every other field will be wrapped inside an `Option`-type, we will need to clone and unwrap them (in our case, we will use expect instead). In addition, it is essential to wrap our type inside a reference counter `Rc`, because it is required to use a construct as a scope.

After we created our construct, we can use it to create our resources. The following example, will show an implementation for a nginx container inside a Kubernetes pod:

```rust
impl NginxBuilder {
	pub fn build(&mut self) -> Rc<Postgres> {
		let this = Rc::new(Postgres {
			name: self.name.clone(),
			scope: self.scope.clone(),
			namespace: self.namespace.clone().expect("missing field 'namespace'"),
			image: self.image.clone().expect("missing field 'image'")
		});

		let name = &this.name;

		tf_bindgen::codegen::resource! {
			&this, resource "kubernetes_pod" "nginx" {
				metadata {
					namespace = &this.namespace
					name = format!("nginx-{name}")
				}
				spec {
					container {
						name = "nginx"
						image = &this.image
						port {
							container_port = 80
						}
					}
				}
			}
		};

		this
	}
}
```

## Outputs

TODO