88
99use std:: error:: Error ;
1010use std:: fmt;
11- #[ cfg( target_os = "linux" ) ]
12- use std:: io:: BufRead ;
1311use std:: num:: { IntErrorKind , ParseIntError } ;
1412
1513use crate :: display:: Quotable ;
14+ #[ cfg( target_os = "linux" ) ]
15+ use procfs:: { Current , Meminfo } ;
1616
1717/// Error arising from trying to compute system memory.
1818enum SystemError {
1919 IOError ,
2020 ParseError ,
21+ #[ cfg( not( target_os = "linux" ) ) ]
2122 NotFound ,
2223}
2324
@@ -43,25 +44,37 @@ impl From<ParseIntError> for SystemError {
4344/// entry in the file.
4445#[ cfg( target_os = "linux" ) ]
4546fn total_physical_memory ( ) -> Result < u128 , SystemError > {
46- // On Linux, the `/proc/meminfo` file has a table with information
47- // about memory usage. For example,
48- //
49- // MemTotal: 7811500 kB
50- // MemFree: 1487876 kB
51- // MemAvailable: 3857232 kB
52- // ...
53- //
54- // We just need to extract the number of `MemTotal`
55- let table = std:: fs:: read ( "/proc/meminfo" ) ?;
56- for line in table. lines ( ) {
57- let line = line?;
58- if line. starts_with ( "MemTotal:" ) && line. ends_with ( "kB" ) {
59- let num_kilobytes: u128 = line[ 9 ..line. len ( ) - 2 ] . trim ( ) . parse ( ) ?;
60- let num_bytes = 1024 * num_kilobytes;
61- return Ok ( num_bytes) ;
47+ let info = Meminfo :: current ( ) . map_err ( |_| SystemError :: IOError ) ?;
48+ Ok ( ( info. mem_total as u128 ) . saturating_mul ( 1024 ) )
49+ }
50+
51+ /// Return the number of bytes of memory that appear to be currently available.
52+ #[ cfg( target_os = "linux" ) ]
53+ pub fn available_memory_bytes ( ) -> Option < u128 > {
54+ let info = Meminfo :: current ( ) . ok ( ) ?;
55+
56+ if let Some ( available_kib) = info. mem_available {
57+ let available_bytes = ( available_kib as u128 ) . saturating_mul ( 1024 ) ;
58+ if available_bytes > 0 {
59+ return Some ( available_bytes) ;
6260 }
6361 }
64- Err ( SystemError :: NotFound )
62+
63+ let fallback_kib = ( info. mem_free as u128 )
64+ . saturating_add ( info. buffers as u128 )
65+ . saturating_add ( info. cached as u128 ) ;
66+
67+ if fallback_kib > 0 {
68+ Some ( fallback_kib. saturating_mul ( 1024 ) )
69+ } else {
70+ total_physical_memory ( ) . ok ( )
71+ }
72+ }
73+
74+ /// Return `None` when the platform does not expose Linux-like `/proc/meminfo`.
75+ #[ cfg( not( target_os = "linux" ) ) ]
76+ pub fn available_memory_bytes ( ) -> Option < u128 > {
77+ None
6578}
6679
6780/// Get the total number of bytes of physical memory.
@@ -361,6 +374,15 @@ pub fn parse_size_u64(size: &str) -> Result<u64, ParseSizeError> {
361374 Parser :: default ( ) . parse_u64 ( size)
362375}
363376
377+ /// Same as `parse_size_u64()`, except 0 fails to parse
378+ pub fn parse_size_non_zero_u64 ( size : & str ) -> Result < u64 , ParseSizeError > {
379+ let v = Parser :: default ( ) . parse_u64 ( size) ?;
380+ if v == 0 {
381+ return Err ( ParseSizeError :: ParseFailure ( "0" . to_string ( ) ) ) ;
382+ }
383+ Ok ( v)
384+ }
385+
364386/// Same as `parse_size_u64()` - deprecated
365387#[ deprecated = "Please use parse_size_u64(size: &str) -> Result<u64, ParseSizeError> OR parse_size_u128(size: &str) -> Result<u128, ParseSizeError> instead." ]
366388pub fn parse_size ( size : & str ) -> Result < u64 , ParseSizeError > {
0 commit comments