Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
### https://github.com/github/gitignore/blob/main/C.gitignore

# Prerequisites
*.d

Expand Down Expand Up @@ -56,3 +58,30 @@ dkms.conf
# https://testanything.org/tap-specification
*.tap
!c/test_report.tap

### https://github.com/github/gitignore/blob/main/Rust.gitignore

# Generated by Cargo
# will have compiled files and executables
debug
target

# These are backup files generated by rustfmt
**/*.rs.bk

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

# Generated by cargo mutants
# Contains mutation testing data
**/mutants.out*/

# rustc will dump stack traces when hitting an internal compiler error to PWD
rustc-ice-*.txt

# RustRover
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/
43 changes: 33 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@

The first project of the School 42.

Linted according to the `norminette` v3.3.51 rules (at the time of writing which was a long time ago) and **not anymore**.
Linted according to the `norminette` v3.3.51 rules (at the time of writing which was a long time ago)... **not anymore**.

## Table of Contents

- [Overview](#overview)
- [Libft in C](#libft-in-c)
- [Libft in Rust](#libft-in-rust)
- [References](#references)
- [C](#c)
- [Rust](#rust)
- [C++](#c++)

### Overview

Expand All @@ -18,29 +22,48 @@ This project was done in C during my learning at the School 42 (School 21). Now

I reorganised the original code and placed it in the [c](./c) directory. To build the project, use `make` or `make bonus` which will create a static "libft.a" library. During my time at School 42, I checked the correctness of the library using the following testing programs (**attention**, these programs are written by people, so rely on them cautiously):

- [libft-unit-test](https://github.com/alelievr/libft-unit-test) (contributed more long time ago)
- [libftTester](https://github.com/Tripouille/libftTester) (contributed less and also long time ago)
- [libft-unit-test](https://github.com/alelievr/libft-unit-test) (contributed a while back)
- [libftTester](https://github.com/Tripouille/libftTester) (contributed some time ago)
- [libft-war-machine](https://github.com/ska42/libft-war-machine)

It is normal (!) if some of your functions are reported as not protected, you don't need to be scared of opinionated "boom" messages..or maybe you have to depending on the School 42 current subject.
It is normal (!) if some of your functions are flagged as unprotected, you don't need to be scared of opinionated "boom" messages (or maybe you have to according to the School 42 latest subject).

Later on, I decided that I needed (for some unexplicable reason) to learn how to write unit tests in C and this project seems to me like a perfect candidate to start with. I picked [Check](https://libcheck.github.io/check/) framework because it is:
Later on, I got into my head that that I need (for some inexplicable reason) to learn how to write unit tests in C and this project seems to me like the perfect place to start. I picked [Check](https://libcheck.github.io/check/) framework because it is:

- installable via `sudo apt install check` (see the [Installing Check](https://libcheck.github.io/check/web/install.html) section for more details);
- simple enough and has some documentation and even tutorials: [basic](https://libcheck.github.io/check/doc/check_html/check_3.html) and [advanced](https://libcheck.github.io/check/doc/check_html/check_4.html#Advanced-Features) + not so-long [API reference](https://libcheck.github.io/check/doc/doxygen/html/check_8h.html);
- advised/required (?) at School 21.
- recommended or even required (?) at School 21.

So, if you are a student or an "intern" at School 21 or 42, you might want to use the "Check" framework in your C projects. Tests are available in the [c/tests](./c/tests) directory. Tests are not organised according to best practices, so please don't expect them to be idiomatic and well-structured. **Disclaimer**: I had and have no eagerness to provide full coverage for this project in C, only functions or data structures of interest that was enough **for me** to master "Check" to some basic level.
So, if you are a student or an "intern" at School 21 or 42, you might want to use the "Check" framework in your C projects. Tests are available in the [c/tests](./c/tests) directory. The tests are not written following best practices, please don’t expect idiomatic or well‑structured code. **Disclaimer**: I had and have no eagerness to provide full coverage for this project in C, only functions or data structures of interest that was enough **for me** to master "Check" to some basic level.

### Libft in Rust

Libft is a library, and I wanted to learn how to build a proper Rust crate—something I could publish and reuse in other projects. This seemed like a good first challenge.

- `cargo new --lib %my-fancy-lib%` - creates a library project/directory with ***%my-fancy-lib%*** name;
- `cargo fmt` - format the code;
- `cargo clippy` - built-in linter;
- `cargo build` - build/compile the project;
- `cargo test` - run tests.

### References

Some of my other 42cursus projects in C:
#### C

Some of my other 42cursus projects in C:
- [get-next-line](https://github.com/stankudrow/get_next_line)
- [ft_printf](https://github.com/stankudrow/ft_printf)

Resources on C programming language:

- [CodeVault playlist](https://www.youtube.com/@CodeVault/playlists) - must watch, practically all videos.

The reason why I won't learn C++ and practice it on the libft -> [have fun](https://www.youtube.com/watch?v=7fGB-hjc2Gc).
#### Rust

- [The Cargo Book][cargo_book_ref] - Cargo is the Rust package manager: dependencies, package compilation, building, uploading to [crates.io package registry](https://crates.io/) etc.

#### C++

No way, thanx. The reason why I won't learn C++ and practice it on the libft -> have fun (or any other emotions) watching [this video](https://www.youtube.com/watch?v=7fGB-hjc2Gc).


[cargo_book_ref]: https://doc.rust-lang.org/cargo/index.html
7 changes: 7 additions & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "libft"
version = "0.1.0"
edition = "2024"

[dependencies]
61 changes: 61 additions & 0 deletions rust/src/ft_chr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// If my goal had been to reproduce the "original" ft_isascii function,
// its signature would have been `pub fn ft_isascii(c: i32) -> i32`,
pub fn ft_isascii(c: u8) -> bool {
// `c >= 0` is redundant when c is unsigned
c <= 127 // the result of the last expression is returned automatically
// however, `return c <= 127;` is doable, yet not idiomatic
}

// A function without `pub` is private -> like `static` in C
fn ft_islower(c: u8) -> bool {
// c >= b'a' && c <= b'z' // possible, but `cargo clippy` suggests...
// (b'a'..=b'z').contains(&c) // yet this also does not please clippy, so...
c.is_ascii_lowercase() // and this makes clippy happy
}

// The following macro will suppress the complain from `cargo clippy`
#[allow(clippy::char_lit_as_u8)]
fn ft_isupper(c: u8) -> bool {
// explicit type casting via `obj as %type%`
// because implicit casting is not ppresumed and for good reason
c >= ('A' as u8) && c <= ('Z' as u8)
}

// No need to declare/define the underlying function before this one
pub fn ft_isalnum(c: u8) -> bool {
ft_isalpha(c) || ft_isdigit(c)
}

pub fn ft_isalpha(c: u8) -> bool {
ft_islower(c) || ft_isupper(c)
}

// several "warnings" are silenced in one macro
#[allow(clippy::char_lit_as_u8, clippy::needless_return)]
pub fn ft_isdigit(c: u8) -> bool {
// b'0' is a byte literal, while '0' is char (Unicode)
// '0' is char, c is u8 -> incompatible types,
// either byte literal will do or explicit type casting
return c >= b'0' && c <= ('9' as u8);
}

#[allow(clippy::needless_return)]
pub fn ft_isprint(c: u8) -> bool {
return c > 31 && c < 127; // not disallowed, why not `return` redundantly
}

pub fn ft_tolower(c: u8) -> u8 {
if ft_isupper(c) {
return c + 32; // here return is necessary
// because the expression above is not the very last
}
c // here the `return` statement can be omitted
}

#[allow(clippy::needless_return)]
pub fn ft_toupper(c: u8) -> u8 {
if ft_islower(c) {
return c - 32; // parentheses are unncecessary
}
return c;
}
14 changes: 14 additions & 0 deletions rust/src/ft_str.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// `pub` = public -> is visible from outside this module.
// Without pub this function would have been private.
pub fn ft_strlen(s: &str) -> usize {
// &str in Rust is UTF-8
// For ASCII string, `s.len() == s.chars().count()`
// C-strlen is about chars as bytes, that is why `s.as_bytes()`

// return s.len(); // return is possible, but redundant
s.len() // no semicolon here!!!

// In a function, the last expression is returned automatically
// If the last expression is followed by a semicolon,
// then it becomes a statement/instruction that returns nothing (semicolon silences).
}
15 changes: 15 additions & 0 deletions rust/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// `pub mod XXX;`
// `mod`ule (file) XXX is claimed to exist.
// `pub` makes this module public, i.e. visible from the outside.
pub mod ft_chr;

pub use ft_chr::ft_isalnum;
pub use ft_chr::ft_isalpha;
pub use ft_chr::ft_isascii;
pub use ft_chr::ft_isdigit;
pub use ft_chr::ft_isprint;
pub use ft_chr::ft_tolower;
pub use ft_chr::ft_toupper;

pub mod ft_str;
pub use ft_str::ft_strlen;
78 changes: 78 additions & 0 deletions rust/tests/test_ft_chr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use libft::ft_isalnum;
use libft::ft_isalpha;
use libft::ft_isascii;
use libft::ft_isdigit;
use libft::ft_isprint;
use libft::ft_tolower;
use libft::ft_toupper;

#[test]
fn test_ft_isalnum() {
assert_eq!(ft_isalnum(0), false);
assert_eq!(ft_isalnum(b'0'), true);
assert_eq!(ft_isalnum(b'o'), true);
assert_eq!(ft_isalnum(b'9'), true);
assert_eq!(ft_isalnum(b'A'), true);
assert_eq!(ft_isalnum(b'Z'), true);
assert_eq!(ft_isalnum(b'a'), true);
assert_eq!(ft_isalnum(b'z'), true);
assert_eq!(ft_isalnum(128), false);
assert_eq!(ft_isalnum(255), false);
}

#[test]
fn test_ft_isalpha() {
assert_eq!(ft_isalpha(0), false);
assert_eq!(ft_isalpha(b'A'), true);
assert_eq!(ft_isalpha(b'Z'), true);
assert_eq!(ft_isalpha(b'a'), true);
assert_eq!(ft_isalpha(b'z'), true);
assert_eq!(ft_isalpha(255), false);
}

#[test]
fn test_ft_isascii() {
assert_eq!(ft_isascii(0), true);
assert_eq!(ft_isascii(100), true);
assert_eq!(ft_isascii(127), true);
assert_eq!(ft_isascii(128), false);
assert_eq!(ft_isascii(255), false);
}

#[test]
fn test_ft_isdigit() {
assert_eq!(ft_isdigit(0), false);
assert_eq!(ft_isdigit(b'0'), true);
assert_eq!(ft_isdigit(b'9'), true);
assert_eq!(ft_isdigit(128), false);
assert_eq!(ft_isdigit(255), false);
}

#[test]
fn test_ft_isprint() {
assert_eq!(ft_isprint(31), false);
assert_eq!(ft_isprint(32), true);
assert_eq!(ft_isprint(100), true);
assert_eq!(ft_isprint(126), true);
assert_eq!(ft_isprint(127), false);
}

#[test]
fn test_ft_tolower() {
assert_eq!(ft_tolower(b'A' - 1), 64);
assert_eq!(ft_tolower(b'A'), b'a');
assert_eq!(ft_tolower(b'Z'), b'z');
assert_eq!(ft_tolower(b'a'), b'a');
assert_eq!(ft_tolower(b'z'), b'z');
assert_eq!(ft_tolower(b'z' + 1), 123);
}

#[test]
fn test_ft_toupper() {
assert_eq!(ft_toupper(b'A' - 1), 64);
assert_eq!(ft_toupper(b'A'), b'A');
assert_eq!(ft_toupper(b'Z'), b'Z');
assert_eq!(ft_toupper(b'a'), b'A');
assert_eq!(ft_toupper(b'z'), b'Z');
assert_eq!(ft_toupper(b'z' + 1), 123);
}
17 changes: 17 additions & 0 deletions rust/tests/test_ft_str.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use libft::ft_strlen;

#[test]
fn test_empty() {
assert_eq!(ft_strlen(""), 0);
}

#[test]
fn test_ascii_only() {
assert_eq!(ft_strlen("hello"), 5);
}

#[test]
fn test_utf8_byte_length() {
let s = "Привет";
assert!(ft_strlen(s) > s.chars().count());
}