1#![forbid(unsafe_code)]
64#![warn(missing_docs, missing_debug_implementations)]
65#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
66#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
67#![cfg_attr(docsrs, feature(doc_cfg))]
68
69use std::{
70 env, fmt,
71 fs::File,
72 io::{Read as _, Write as _},
73 path::Path,
74 time::Duration,
75};
76
77use actix_http::{Request, Response};
78use actix_service::IntoServiceFactory;
79use actix_web::{
80 body::MessageBody,
81 dev::{AppConfig, ServiceFactory},
82 http::KeepAlive as ActixKeepAlive,
83 Error as WebError, HttpServer,
84};
85use serde::{de, Deserialize};
86
87#[macro_use]
88mod error;
89mod parse;
90mod settings;
91
92#[cfg(all(feature = "openssl", feature = "rustls-0_23", not(docsrs)))]
93compile_error!("`actix-settings` supports only one TLS backend feature at a time");
94
95#[cfg(any(feature = "openssl", feature = "rustls-0_23"))]
96pub use self::settings::Tls;
97pub use self::{
98 error::Error,
99 parse::Parse,
100 settings::{
101 ActixSettings, Address, Backlog, KeepAlive, MaxConnectionRate, MaxConnections, Mode,
102 NumWorkers, Timeout,
103 },
104};
105
106type AsResult<T> = std::result::Result<T, Error>;
108
109#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
111#[serde(bound = "A: Deserialize<'de>")]
112pub struct BasicSettings<A> {
113 pub actix: ActixSettings,
115
116 pub application: A,
118}
119
120pub type Settings = BasicSettings<NoSettings>;
122
123#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
125#[non_exhaustive]
126pub struct NoSettings {}
127
128impl<A> BasicSettings<A>
129where
130 A: de::DeserializeOwned,
131{
132 pub(crate) const DEFAULT_TOML_TEMPLATE: &'static str = include_str!("./defaults.toml");
137
138 pub fn parse_toml<P>(filepath: P) -> AsResult<Self>
143 where
144 P: AsRef<Path>,
145 {
146 let filepath = filepath.as_ref();
147
148 if !filepath.exists() {
149 Self::write_toml_file(filepath)?;
150 }
151
152 let mut f = File::open(filepath)?;
153 let len_guess = f.metadata().map(|md| md.len()).unwrap_or(128);
154
155 let mut contents = String::with_capacity(len_guess as usize);
156 f.read_to_string(&mut contents)?;
157
158 Ok(toml::from_str::<Self>(&contents)?)
159 }
160
161 pub fn from_default_template() -> Self {
163 Self::from_template(Self::DEFAULT_TOML_TEMPLATE).unwrap()
164 }
165
166 pub fn from_template(template: &str) -> AsResult<Self> {
168 Ok(toml::from_str(template)?)
169 }
170
171 pub fn write_toml_file<P>(filepath: P) -> AsResult<()>
178 where
179 P: AsRef<Path>,
180 {
181 let filepath = filepath.as_ref();
182
183 if filepath.exists() {
184 return Err(Error::FileExists(filepath.to_path_buf()));
185 }
186
187 let mut file = File::create(filepath)?;
188 file.write_all(Self::DEFAULT_TOML_TEMPLATE.trim().as_bytes())?;
189 file.flush()?;
190
191 Ok(())
192 }
193
194 pub fn override_field<F, V>(field: &mut F, value: V) -> AsResult<()>
209 where
210 F: Parse,
211 V: AsRef<str>,
212 {
213 *field = F::parse(value.as_ref())?;
214 Ok(())
215 }
216
217 pub fn override_field_with_env_var<F, N>(field: &mut F, var_name: N) -> AsResult<()>
234 where
235 F: Parse,
236 N: AsRef<str>,
237 {
238 match env::var(var_name.as_ref()) {
239 Err(env::VarError::NotPresent) => Ok(()),
240 Err(var_error) => Err(Error::from(var_error)),
241 Ok(value) => Self::override_field(field, value),
242 }
243 }
244}
245
246pub trait ApplySettings<S>: Sized {
248 #[deprecated = "Prefer `try_apply_settings()`."]
258 fn apply_settings(self, settings: &S) -> Self {
259 self.try_apply_settings(settings)
260 .expect("Could not apply settings")
261 }
262
263 fn try_apply_settings(self, settings: &S) -> AsResult<Self>;
269}
270
271impl<F, I, S, B> ApplySettings<ActixSettings> for HttpServer<F, I, S, B>
272where
273 F: Fn() -> I + Send + Clone + 'static,
274 I: IntoServiceFactory<S, Request>,
275 S: ServiceFactory<Request, Config = AppConfig> + 'static,
276 S::Error: Into<WebError> + 'static,
277 S::InitError: fmt::Debug,
278 S::Response: Into<Response<B>> + 'static,
279 S::Future: 'static,
280 B: MessageBody + 'static,
281{
282 fn apply_settings(self, settings: &ActixSettings) -> Self {
283 self.try_apply_settings(settings).unwrap()
284 }
285
286 fn try_apply_settings(mut self, settings: &ActixSettings) -> AsResult<Self> {
287 for Address { host, port } in &settings.hosts {
288 #[cfg(feature = "openssl")]
289 {
290 if settings.tls.enabled {
291 self = self.bind_openssl(
292 format!("{host}:{port}"),
293 settings.tls.get_ssl_acceptor_builder()?,
294 )?;
295 } else {
296 self = self.bind(format!("{host}:{port}"))?;
297 }
298 }
299
300 #[cfg(feature = "rustls-0_23")]
301 {
302 if settings.tls.enabled {
303 self = self.bind_rustls_0_23(
304 format!("{host}:{port}"),
305 settings.tls.get_rustls_0_23_server_config()?,
306 )?;
307 } else {
308 self = self.bind(format!("{host}:{port}"))?;
309 }
310 }
311
312 #[cfg(not(any(feature = "openssl", feature = "rustls-0_23")))]
313 {
314 self = self.bind(format!("{host}:{port}"))?;
315 }
316 }
317
318 self = match settings.num_workers {
319 NumWorkers::Default => self,
320 NumWorkers::Manual(n) => self.workers(n),
321 };
322
323 self = match settings.backlog {
324 Backlog::Default => self,
325 Backlog::Manual(n) => self.backlog(n as u32),
326 };
327
328 self = match settings.max_connections {
329 MaxConnections::Default => self,
330 MaxConnections::Manual(n) => self.max_connections(n),
331 };
332
333 self = match settings.max_connection_rate {
334 MaxConnectionRate::Default => self,
335 MaxConnectionRate::Manual(n) => self.max_connection_rate(n),
336 };
337
338 self = match settings.keep_alive {
339 KeepAlive::Default => self,
340 KeepAlive::Disabled => self.keep_alive(ActixKeepAlive::Disabled),
341 KeepAlive::Os => self.keep_alive(ActixKeepAlive::Os),
342 KeepAlive::Seconds(n) => self.keep_alive(Duration::from_secs(n as u64)),
343 };
344
345 self = match settings.client_timeout {
346 Timeout::Default => self,
347 Timeout::Milliseconds(n) => {
348 self.client_request_timeout(Duration::from_millis(n as u64))
349 }
350 Timeout::Seconds(n) => self.client_request_timeout(Duration::from_secs(n as u64)),
351 };
352
353 self = match settings.client_shutdown {
354 Timeout::Default => self,
355 Timeout::Milliseconds(n) => {
356 self.client_disconnect_timeout(Duration::from_millis(n as u64))
357 }
358 Timeout::Seconds(n) => self.client_disconnect_timeout(Duration::from_secs(n as u64)),
359 };
360
361 self = match settings.shutdown_timeout {
362 Timeout::Default => self,
363 Timeout::Milliseconds(_) => self.shutdown_timeout(1),
364 Timeout::Seconds(n) => self.shutdown_timeout(n as u64),
365 };
366
367 Ok(self)
368 }
369}
370
371impl<F, I, S, B, A> ApplySettings<BasicSettings<A>> for HttpServer<F, I, S, B>
372where
373 F: Fn() -> I + Send + Clone + 'static,
374 I: IntoServiceFactory<S, Request>,
375 S: ServiceFactory<Request, Config = AppConfig> + 'static,
376 S::Error: Into<WebError> + 'static,
377 S::InitError: fmt::Debug,
378 S::Response: Into<Response<B>> + 'static,
379 S::Future: 'static,
380 B: MessageBody + 'static,
381 A: de::DeserializeOwned,
382{
383 fn apply_settings(self, settings: &BasicSettings<A>) -> Self {
384 self.try_apply_settings(&settings.actix).unwrap()
385 }
386
387 fn try_apply_settings(self, settings: &BasicSettings<A>) -> AsResult<Self> {
388 self.try_apply_settings(&settings.actix)
389 }
390}
391
392#[cfg(test)]
393mod tests {
394 use actix_web::App;
395
396 use super::*;
397
398 #[test]
399 fn apply_settings() {
400 let settings = Settings::parse_toml("Server.toml").unwrap();
401 let server = HttpServer::new(App::new).try_apply_settings(&settings);
402 assert!(server.is_ok());
403 }
404
405 #[test]
406 fn override_field_hosts() {
407 let mut settings = Settings::from_default_template();
408
409 assert_eq!(
410 settings.actix.hosts,
411 vec![Address {
412 host: "0.0.0.0".into(),
413 port: 9000
414 },]
415 );
416
417 Settings::override_field(
418 &mut settings.actix.hosts,
419 r#"[
420 ["0.0.0.0", 1234],
421 ["localhost", 2345]
422 ]"#,
423 )
424 .unwrap();
425
426 assert_eq!(
427 settings.actix.hosts,
428 vec![
429 Address {
430 host: "0.0.0.0".into(),
431 port: 1234
432 },
433 Address {
434 host: "localhost".into(),
435 port: 2345
436 },
437 ]
438 );
439 }
440
441 #[test]
442 fn override_field_with_env_var_hosts() {
443 let mut settings = Settings::from_default_template();
444
445 assert_eq!(
446 settings.actix.hosts,
447 vec![Address {
448 host: "0.0.0.0".into(),
449 port: 9000
450 },]
451 );
452
453 std::env::set_var(
454 "OVERRIDE__HOSTS",
455 r#"[
456 ["0.0.0.0", 1234],
457 ["localhost", 2345]
458 ]"#,
459 );
460
461 Settings::override_field_with_env_var(&mut settings.actix.hosts, "OVERRIDE__HOSTS")
462 .unwrap();
463
464 assert_eq!(
465 settings.actix.hosts,
466 vec![
467 Address {
468 host: "0.0.0.0".into(),
469 port: 1234
470 },
471 Address {
472 host: "localhost".into(),
473 port: 2345
474 },
475 ]
476 );
477 }
478
479 #[test]
480 fn override_field_mode() {
481 let mut settings = Settings::from_default_template();
482 assert_eq!(settings.actix.mode, Mode::Development);
483 Settings::override_field(&mut settings.actix.mode, "production").unwrap();
484 assert_eq!(settings.actix.mode, Mode::Production);
485 }
486
487 #[test]
488 fn override_field_with_env_var_mode() {
489 let mut settings = Settings::from_default_template();
490 assert_eq!(settings.actix.mode, Mode::Development);
491 std::env::set_var("OVERRIDE__MODE", "production");
492 Settings::override_field_with_env_var(&mut settings.actix.mode, "OVERRIDE__MODE").unwrap();
493 assert_eq!(settings.actix.mode, Mode::Production);
494 }
495
496 #[test]
497 fn override_field_enable_compression() {
498 let mut settings = Settings::from_default_template();
499 assert!(settings.actix.enable_compression);
500 Settings::override_field(&mut settings.actix.enable_compression, "false").unwrap();
501 assert!(!settings.actix.enable_compression);
502 }
503
504 #[test]
505 fn override_field_with_env_var_enable_compression() {
506 let mut settings = Settings::from_default_template();
507 assert!(settings.actix.enable_compression);
508 std::env::set_var("OVERRIDE__ENABLE_COMPRESSION", "false");
509 Settings::override_field_with_env_var(
510 &mut settings.actix.enable_compression,
511 "OVERRIDE__ENABLE_COMPRESSION",
512 )
513 .unwrap();
514 assert!(!settings.actix.enable_compression);
515 }
516
517 #[test]
518 fn override_field_enable_log() {
519 let mut settings = Settings::from_default_template();
520 assert!(settings.actix.enable_log);
521 Settings::override_field(&mut settings.actix.enable_log, "false").unwrap();
522 assert!(!settings.actix.enable_log);
523 }
524
525 #[test]
526 fn override_field_with_env_var_enable_log() {
527 let mut settings = Settings::from_default_template();
528 assert!(settings.actix.enable_log);
529 std::env::set_var("OVERRIDE__ENABLE_LOG", "false");
530 Settings::override_field_with_env_var(
531 &mut settings.actix.enable_log,
532 "OVERRIDE__ENABLE_LOG",
533 )
534 .unwrap();
535 assert!(!settings.actix.enable_log);
536 }
537
538 #[test]
539 fn override_field_num_workers() {
540 let mut settings = Settings::from_default_template();
541 assert_eq!(settings.actix.num_workers, NumWorkers::Default);
542 Settings::override_field(&mut settings.actix.num_workers, "42").unwrap();
543 assert_eq!(settings.actix.num_workers, NumWorkers::Manual(42));
544 }
545
546 #[test]
547 fn override_field_with_env_var_num_workers() {
548 let mut settings = Settings::from_default_template();
549 assert_eq!(settings.actix.num_workers, NumWorkers::Default);
550 std::env::set_var("OVERRIDE__NUM_WORKERS", "42");
551 Settings::override_field_with_env_var(
552 &mut settings.actix.num_workers,
553 "OVERRIDE__NUM_WORKERS",
554 )
555 .unwrap();
556 assert_eq!(settings.actix.num_workers, NumWorkers::Manual(42));
557 }
558
559 #[test]
560 fn override_field_backlog() {
561 let mut settings = Settings::from_default_template();
562 assert_eq!(settings.actix.backlog, Backlog::Default);
563 Settings::override_field(&mut settings.actix.backlog, "42").unwrap();
564 assert_eq!(settings.actix.backlog, Backlog::Manual(42));
565 }
566
567 #[test]
568 fn override_field_with_env_var_backlog() {
569 let mut settings = Settings::from_default_template();
570 assert_eq!(settings.actix.backlog, Backlog::Default);
571 std::env::set_var("OVERRIDE__BACKLOG", "42");
572 Settings::override_field_with_env_var(&mut settings.actix.backlog, "OVERRIDE__BACKLOG")
573 .unwrap();
574 assert_eq!(settings.actix.backlog, Backlog::Manual(42));
575 }
576
577 #[test]
578 fn override_field_max_connections() {
579 let mut settings = Settings::from_default_template();
580 assert_eq!(settings.actix.max_connections, MaxConnections::Default);
581 Settings::override_field(&mut settings.actix.max_connections, "42").unwrap();
582 assert_eq!(settings.actix.max_connections, MaxConnections::Manual(42));
583 }
584
585 #[test]
586 fn override_field_with_env_var_max_connections() {
587 let mut settings = Settings::from_default_template();
588 assert_eq!(settings.actix.max_connections, MaxConnections::Default);
589 std::env::set_var("OVERRIDE__MAX_CONNECTIONS", "42");
590 Settings::override_field_with_env_var(
591 &mut settings.actix.max_connections,
592 "OVERRIDE__MAX_CONNECTIONS",
593 )
594 .unwrap();
595 assert_eq!(settings.actix.max_connections, MaxConnections::Manual(42));
596 }
597
598 #[test]
599 fn override_field_max_connection_rate() {
600 let mut settings = Settings::from_default_template();
601 assert_eq!(
602 settings.actix.max_connection_rate,
603 MaxConnectionRate::Default
604 );
605 Settings::override_field(&mut settings.actix.max_connection_rate, "42").unwrap();
606 assert_eq!(
607 settings.actix.max_connection_rate,
608 MaxConnectionRate::Manual(42)
609 );
610 }
611
612 #[test]
613 fn override_field_with_env_var_max_connection_rate() {
614 let mut settings = Settings::from_default_template();
615 assert_eq!(
616 settings.actix.max_connection_rate,
617 MaxConnectionRate::Default
618 );
619 std::env::set_var("OVERRIDE__MAX_CONNECTION_RATE", "42");
620 Settings::override_field_with_env_var(
621 &mut settings.actix.max_connection_rate,
622 "OVERRIDE__MAX_CONNECTION_RATE",
623 )
624 .unwrap();
625 assert_eq!(
626 settings.actix.max_connection_rate,
627 MaxConnectionRate::Manual(42)
628 );
629 }
630
631 #[test]
632 fn override_field_keep_alive() {
633 let mut settings = Settings::from_default_template();
634 assert_eq!(settings.actix.keep_alive, KeepAlive::Default);
635 Settings::override_field(&mut settings.actix.keep_alive, "42 seconds").unwrap();
636 assert_eq!(settings.actix.keep_alive, KeepAlive::Seconds(42));
637 }
638
639 #[test]
640 fn override_field_with_env_var_keep_alive() {
641 let mut settings = Settings::from_default_template();
642 assert_eq!(settings.actix.keep_alive, KeepAlive::Default);
643 std::env::set_var("OVERRIDE__KEEP_ALIVE", "42 seconds");
644 Settings::override_field_with_env_var(
645 &mut settings.actix.keep_alive,
646 "OVERRIDE__KEEP_ALIVE",
647 )
648 .unwrap();
649 assert_eq!(settings.actix.keep_alive, KeepAlive::Seconds(42));
650 }
651
652 #[test]
653 fn override_field_client_timeout() {
654 let mut settings = Settings::from_default_template();
655 assert_eq!(settings.actix.client_timeout, Timeout::Default);
656 Settings::override_field(&mut settings.actix.client_timeout, "42 seconds").unwrap();
657 assert_eq!(settings.actix.client_timeout, Timeout::Seconds(42));
658 }
659
660 #[test]
661 fn override_field_with_env_var_client_timeout() {
662 let mut settings = Settings::from_default_template();
663 assert_eq!(settings.actix.client_timeout, Timeout::Default);
664 std::env::set_var("OVERRIDE__CLIENT_TIMEOUT", "42 seconds");
665 Settings::override_field_with_env_var(
666 &mut settings.actix.client_timeout,
667 "OVERRIDE__CLIENT_TIMEOUT",
668 )
669 .unwrap();
670 assert_eq!(settings.actix.client_timeout, Timeout::Seconds(42));
671 }
672
673 #[test]
674 fn override_field_client_shutdown() {
675 let mut settings = Settings::from_default_template();
676 assert_eq!(settings.actix.client_shutdown, Timeout::Default);
677 Settings::override_field(&mut settings.actix.client_shutdown, "42 seconds").unwrap();
678 assert_eq!(settings.actix.client_shutdown, Timeout::Seconds(42));
679 }
680
681 #[test]
682 fn override_field_with_env_var_client_shutdown() {
683 let mut settings = Settings::from_default_template();
684 assert_eq!(settings.actix.client_shutdown, Timeout::Default);
685 std::env::set_var("OVERRIDE__CLIENT_SHUTDOWN", "42 seconds");
686 Settings::override_field_with_env_var(
687 &mut settings.actix.client_shutdown,
688 "OVERRIDE__CLIENT_SHUTDOWN",
689 )
690 .unwrap();
691 assert_eq!(settings.actix.client_shutdown, Timeout::Seconds(42));
692 }
693
694 #[test]
695 fn override_field_shutdown_timeout() {
696 let mut settings = Settings::from_default_template();
697 assert_eq!(settings.actix.shutdown_timeout, Timeout::Default);
698 Settings::override_field(&mut settings.actix.shutdown_timeout, "42 seconds").unwrap();
699 assert_eq!(settings.actix.shutdown_timeout, Timeout::Seconds(42));
700 }
701
702 #[test]
703 fn override_field_with_env_var_shutdown_timeout() {
704 let mut settings = Settings::from_default_template();
705 assert_eq!(settings.actix.shutdown_timeout, Timeout::Default);
706 std::env::set_var("OVERRIDE__SHUTDOWN_TIMEOUT", "42 seconds");
707 Settings::override_field_with_env_var(
708 &mut settings.actix.shutdown_timeout,
709 "OVERRIDE__SHUTDOWN_TIMEOUT",
710 )
711 .unwrap();
712 assert_eq!(settings.actix.shutdown_timeout, Timeout::Seconds(42));
713 }
714
715 #[cfg(any(feature = "openssl", feature = "rustls-0_23"))]
716 #[test]
717 fn override_field_tls_enabled() {
718 let mut settings = Settings::from_default_template();
719 assert!(!settings.actix.tls.enabled);
720 Settings::override_field(&mut settings.actix.tls.enabled, "true").unwrap();
721 assert!(settings.actix.tls.enabled);
722 }
723
724 #[cfg(any(feature = "openssl", feature = "rustls-0_23"))]
725 #[test]
726 fn override_field_with_env_var_tls_enabled() {
727 let mut settings = Settings::from_default_template();
728 assert!(!settings.actix.tls.enabled);
729 std::env::set_var("OVERRIDE__TLS_ENABLED", "true");
730 Settings::override_field_with_env_var(
731 &mut settings.actix.tls.enabled,
732 "OVERRIDE__TLS_ENABLED",
733 )
734 .unwrap();
735 assert!(settings.actix.tls.enabled);
736 }
737
738 #[cfg(any(feature = "openssl", feature = "rustls-0_23"))]
739 #[test]
740 fn override_field_tls_certificate() {
741 let mut settings = Settings::from_default_template();
742 assert_eq!(
743 settings.actix.tls.certificate,
744 Path::new("path/to/cert/cert.pem")
745 );
746 Settings::override_field(
747 &mut settings.actix.tls.certificate,
748 "/overridden/path/to/cert/cert.pem",
749 )
750 .unwrap();
751 assert_eq!(
752 settings.actix.tls.certificate,
753 Path::new("/overridden/path/to/cert/cert.pem")
754 );
755 }
756
757 #[cfg(any(feature = "openssl", feature = "rustls-0_23"))]
758 #[test]
759 fn override_field_with_env_var_tls_certificate() {
760 let mut settings = Settings::from_default_template();
761 assert_eq!(
762 settings.actix.tls.certificate,
763 Path::new("path/to/cert/cert.pem")
764 );
765 std::env::set_var(
766 "OVERRIDE__TLS_CERTIFICATE",
767 "/overridden/path/to/cert/cert.pem",
768 );
769 Settings::override_field_with_env_var(
770 &mut settings.actix.tls.certificate,
771 "OVERRIDE__TLS_CERTIFICATE",
772 )
773 .unwrap();
774 assert_eq!(
775 settings.actix.tls.certificate,
776 Path::new("/overridden/path/to/cert/cert.pem")
777 );
778 }
779
780 #[cfg(any(feature = "openssl", feature = "rustls-0_23"))]
781 #[test]
782 fn override_field_tls_private_key() {
783 let mut settings = Settings::from_default_template();
784 assert_eq!(
785 settings.actix.tls.private_key,
786 Path::new("path/to/cert/key.pem")
787 );
788 Settings::override_field(
789 &mut settings.actix.tls.private_key,
790 "/overridden/path/to/cert/key.pem",
791 )
792 .unwrap();
793 assert_eq!(
794 settings.actix.tls.private_key,
795 Path::new("/overridden/path/to/cert/key.pem")
796 );
797 }
798
799 #[cfg(any(feature = "openssl", feature = "rustls-0_23"))]
800 #[test]
801 fn override_field_with_env_var_tls_private_key() {
802 let mut settings = Settings::from_default_template();
803 assert_eq!(
804 settings.actix.tls.private_key,
805 Path::new("path/to/cert/key.pem")
806 );
807 std::env::set_var(
808 "OVERRIDE__TLS_PRIVATE_KEY",
809 "/overridden/path/to/cert/key.pem",
810 );
811 Settings::override_field_with_env_var(
812 &mut settings.actix.tls.private_key,
813 "OVERRIDE__TLS_PRIVATE_KEY",
814 )
815 .unwrap();
816 assert_eq!(
817 settings.actix.tls.private_key,
818 Path::new("/overridden/path/to/cert/key.pem")
819 );
820 }
821
822 #[test]
823 fn override_extended_field_with_custom_type() {
824 #[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
825 struct NestedSetting {
826 foo: String,
827 bar: bool,
828 }
829
830 #[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
831 #[serde(rename_all = "kebab-case")]
832 struct AppSettings {
833 example_name: String,
834 nested_field: NestedSetting,
835 }
836
837 type CustomSettings = BasicSettings<AppSettings>;
838
839 let mut settings = CustomSettings::from_template(
840 &(CustomSettings::DEFAULT_TOML_TEMPLATE.to_string()
841 + "\nexample-name = \"example value\""
843 + "\nnested-field = { foo = \"foo\", bar = false }"),
844 )
845 .unwrap();
846
847 assert_eq!(
848 settings.application,
849 AppSettings {
850 example_name: "example value".into(),
851 nested_field: NestedSetting {
852 foo: "foo".into(),
853 bar: false,
854 },
855 }
856 );
857
858 CustomSettings::override_field(
859 &mut settings.application.example_name,
860 "/overridden/path/to/cert/key.pem",
861 )
862 .unwrap();
863
864 assert_eq!(
865 settings.application,
866 AppSettings {
867 example_name: "/overridden/path/to/cert/key.pem".into(),
868 nested_field: NestedSetting {
869 foo: "foo".into(),
870 bar: false,
871 },
872 }
873 );
874 }
875}